diff --git a/bootstrap.php b/bootstrap.php
index 794613840f288b9f3dde80176777593f5c4243c2..4b64227a839c1e9cd864db6cc74a1930e9906f98 100644
--- a/bootstrap.php
+++ b/bootstrap.php
@@ -139,6 +139,7 @@ class Bootstrap {
         define('QUEUE_SORT_TABLE', $prefix.'queue_sort');
         define('QUEUE_SORTING_TABLE', $prefix.'queue_sorts');
         define('QUEUE_EXPORT_TABLE', $prefix.'queue_export');
+        define('QUEUE_CONFIG_TABLE', $prefix.'queue_config');
 
         define('API_KEY_TABLE',$prefix.'api_key');
         define('TIMEZONE_TABLE',$prefix.'timezone');
diff --git a/include/ajax.search.php b/include/ajax.search.php
index 80ebd621ca61503df97026c1f196d8c7e199ba87..d8ce8dbab1b4ef7443b5a3b664cdac63f3ce4425 100644
--- a/include/ajax.search.php
+++ b/include/ajax.search.php
@@ -28,8 +28,9 @@ class SearchAjaxAPI extends AjaxController {
         if (!$thisstaff)
             Http::response(403, 'Agent login required');
 
-        $search = new SavedSearch(array(
+        $search = new AdhocSearch(array(
             'root' => 'T',
+            'staff_id' => $thisstaff->getId(),
             'parent_id' => @$_GET['parent_id'] ?: 0,
         ));
         if ($search->parent_id) {
@@ -39,7 +40,7 @@ class SearchAjaxAPI extends AjaxController {
         if (isset($_SESSION[$context]) && $key && $_SESSION[$context][$key])
             $search->config = $_SESSION[$context][$key];
 
-        $this->_tryAgain($search, $search->getForm());
+        $this->_tryAgain($search);
     }
 
     function editSearch($id) {
@@ -51,7 +52,7 @@ class SearchAjaxAPI extends AjaxController {
         elseif (!$search || !$search->checkAccess($thisstaff))
             Http::response(404, 'No such saved search');
 
-        $this->_tryAgain($search, $search->getForm());
+        $this->_tryAgain($search);
     }
 
     function addField($name) {
@@ -60,7 +61,9 @@ class SearchAjaxAPI extends AjaxController {
         if (!$thisstaff)
             Http::response(403, 'Agent login required');
 
-        $search = new SavedSearch(array('root'=>'T'));
+        $search = new SavedSearch(array(
+                    'root'=>'T'
+                    ));
         $searchable = $search->getSupportedMatches();
         if (!($F = $searchable[$name]))
             Http::response(404, 'No such field: ', print_r($name, true));
@@ -82,7 +85,15 @@ class SearchAjaxAPI extends AjaxController {
     }
 
     function doSearch() {
-        $search = new SavedSearch(array('root' => 'T'));
+        global $thisstaff;
+
+        if (!$thisstaff)
+            Http::response(403, 'Agent login is required');
+
+        $search = new AdhocSearch(array(
+                    'root' => 'T',
+                    'staff_id' => $thisstaff->getId()));
+
         $form = $search->getForm($_POST);
         if (false === $this->_setupSearch($search, $form)) {
             return;
@@ -139,11 +150,28 @@ class SearchAjaxAPI extends AjaxController {
             -$size);
     }
 
-    function _tryAgain($search, $form, $errors=array(), $info=array()) {
-        $matches = $search->getSupportedMatches();
+    function _tryAgain($search, $form=null, $errors=array(), $info=array()) {
+        if (!$form)
+            $form = $search->getForm();
         include STAFFINC_DIR . 'templates/advanced-search.tmpl.php';
     }
 
+    function createSearch() {
+        global $thisstaff;
+
+        if (!$thisstaff)
+            Http::response(403, 'Agent login is required');
+
+
+        $search = SavedSearch::create(array(
+                    'title' => __('Add Queue'),
+                    'root' => 'T',
+                    'staff_id' => $thisstaff->getId(),
+                    'parent_id' =>  $_GET['pid'],
+                    ));
+        $this->_tryAgain($search);
+    }
+
     function saveSearch($id=0) {
         global $thisstaff;
 
@@ -151,15 +179,16 @@ class SearchAjaxAPI extends AjaxController {
             Http::response(403, 'Agent login is required');
 
         if ($id) { //  update
-            $search = SavedSearch::lookup($id);
+            if (!($search = SavedSearch::lookup($id))
+                    || !$search->checkAccess($thisstaff))
+                Http::response(404, 'No such saved search');
         } else { // new search
-            $search = SavedSearch::create(array('root' => 'T'));
-            $search->staff_id = $thisstaff->getId();
+            $search = SavedSearch::create(array(
+                        'root' => 'T',
+                        'staff_id' => $thisstaff->getId()
+                        ));
         }
 
-        if (!$search || !$search->checkAccess($thisstaff))
-            Http::response(404, 'No such saved search');
-
         if (false === $this->_saveSearch($search))
             return;
 
@@ -169,16 +198,23 @@ class SearchAjaxAPI extends AjaxController {
                     $id ? __('updated') : __('created'),
                     __('successfully')),
                 );
-
-        $this->_tryAgain($search, $search->getForm(), null, $info);
+        $this->_tryAgain($search, null, null, $info);
     }
 
     function _saveSearch(SavedSearch $search) {
+
+        // Validate the form.
         $form = $search->getForm($_POST);
+        if ($this->_hasErrors($search, $form))
+            return false;
+
         $errors = array();
         if (!$search->update($_POST, $errors)
-            || !$search->save(true)
-        ) {
+                || !$search->save(true)) {
+
+            $form->addError(sprintf(
+                        __('Unable to update %s. Correct error(s) below and try again.'),
+                        __('queue')));
             $this->_tryAgain($search, $form, $errors);
             return false;
         }
@@ -352,43 +388,15 @@ class SearchAjaxAPI extends AjaxController {
     function collectQueueCounts($ids=null) {
         global $thisstaff;
 
-        if (!$thisstaff) {
+        if (!$thisstaff)
             Http::response(403, 'Agent login is required');
-        }
-
-        $queues = CustomQueue::objects()
-            ->filter(Q::any(array(
-                'flags__hasbit' => CustomQueue::FLAG_PUBLIC,
-                'staff_id' => $thisstaff->getId(),
-            )));
 
+        $criteria = array();
         if ($ids && is_array($ids))
-            $queues->filter(array('id__in' => $ids));
-
-        $query = Ticket::objects();
-
-        // Visibility contraints ------------------
-        // TODO: Consider SavedSearch::ignoreVisibilityConstraints()
-        $visibility = $thisstaff->getTicketsVisibility();
-        $query->filter($visibility);
-        foreach ($queues as $queue) {
-            $Q = $queue->getBasicQuery();
-            if (count($Q->extra) || $Q->isWindowed()) {
-                // XXX: This doesn't work
-                $query->annotate(array(
-                    'q'.$queue->id => $Q->values_flat()
-                        ->aggregate(array('count' => SqlAggregate::COUNT('ticket_id')))
-                ));
-            }
-            else {
-                $expr = SqlCase::N()->when(new SqlExpr(new Q($Q->constraints)), new SqlField('ticket_id'));
-                $query->aggregate(array(
-                    'q'.$queue->id => SqlAggregate::COUNT($expr, true)
-                ));
-            }
-        }
+            $criteria = array('id__in' => $ids);
 
+        $counts = SavedQueue::ticketsCount($thisstaff, $criteria, 'q');
         Http::response(200, false, 'application/json');
-        return $this->encode($query->values()->one());
+        return $this->encode($counts);
     }
 }
diff --git a/include/class.forms.php b/include/class.forms.php
index cc6572a3efdac509067b256d34f5a5df7a35de8f..9ef27efb5e8385b313159ef4505edd625ffa14b0 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -1650,6 +1650,15 @@ class BooleanField extends FormField {
         );
     }
 
+    function describeSearchMethod($method) {
+
+        $methods = $this->get('descsearchmethods');
+        if (isset($methods[$method]))
+            return $methods[$method];
+
+        return parent::describeSearchMethod($method);
+    }
+
     function getSearchMethodWidgets() {
         return array(
             'set' => null,
diff --git a/include/class.queue.php b/include/class.queue.php
index ed296cd358dd17a7cd3bf3abac966cfba61b7e37..189a7a84654a2bda283c60e0a49eae443ab142e8 100644
--- a/include/class.queue.php
+++ b/include/class.queue.php
@@ -28,6 +28,7 @@ class CustomQueue extends VerySimpleModel {
             ),
             'columns' => array(
                 'reverse' => 'QueueColumnGlue.queue',
+                'constrain' => array('staff_id' =>'QueueColumnGlue.staff_id'),
                 'broker' => 'QueueColumnListBroker',
             ),
             'sorts' => array(
@@ -111,6 +112,10 @@ class CustomQueue extends VerySimpleModel {
         return $this->path ?: $this->buildPath();
     }
 
+    function criteriaRequired() {
+        return true;
+    }
+
     function getCriteria($include_parent=false) {
         if (!isset($this->criteria)) {
             $old = @$this->config[0] === '{';
@@ -164,38 +169,40 @@ class CustomQueue extends VerySimpleModel {
      * Parameters:
      * $search - <array> Request parameters ($_POST) used to update the
      *      search beyond the current configuration of the search criteria
+     * $searchables - search fields - default to current if not provided
      */
-    function getForm($source=null) {
-        $searchable = $this->getCurrentSearchFields($source);
-        $fields = array(
-            ':keywords' => new TextboxField(array(
-                'id' => 3001,
-                'configuration' => array(
-                    'size' => 40,
-                    'length' => 400,
-                    'autofocus' => true,
-                    'classes' => 'full-width headline',
-                    'placeholder' => __('Keywords — Optional'),
-                ),
-            )),
-        );
-        foreach ($searchable as $path=>$field) {
-            $fields = array_merge($fields, static::getSearchField($field, $path));
+    function getForm($source=null, $searchable=null) {
+        $fields = array();
+        $validator = false;
+        if (!isset($searchable)) {
+            $searchable = $this->getCurrentSearchFields($source);
+            $validator = true;
+            $fields = array(
+                ':keywords' => new TextboxField(array(
+                    'id' => 3001,
+                    'configuration' => array(
+                        'size' => 40,
+                        'length' => 400,
+                        'autofocus' => true,
+                        'classes' => 'full-width headline',
+                        'placeholder' => __('Keywords — Optional'),
+                    ),
+                )),
+            );
         }
 
+        foreach ($searchable as $path=>$field)
+            $fields = array_merge($fields, static::getSearchField($field, $path));
+
         $form = new AdvancedSearchForm($fields, $source);
-        $form->addValidator(function($form) {
-            $selected = 0;
-            foreach ($form->getFields() as $F) {
-                if (substr($F->get('name'), -7) == '+search' && $F->getClean())
-                    $selected += 1;
-                // Consider keyword searches
-                elseif ($F->get('name') == ':keywords' && $F->getClean())
-                    $selected += 1;
-            }
-            if (!$selected)
-                $form->addError(__('No fields selected for searching'));
-        });
+
+        // Field selection validator
+        if ($this->criteriaRequired()) {
+            $form->addValidator(function($form) {
+                    if (!$form->getNumFieldsSelected())
+                        $form->addError(__('No fields selected for searching'));
+                });
+        }
 
         // Load state from current configuraiton
         if (!$source) {
@@ -235,7 +242,7 @@ class CustomQueue extends VerySimpleModel {
      *      to contain a list extra fields by ORM path, of newly added
      *      fields not yet saved in this object's getCriteria().
      */
-    function getCurrentSearchFields($source=array()) {
+    function getCurrentSearchFields($source=array(), $criteria=array()) {
         static $basic = array(
             'Ticket' => array(
                 'status__state',
@@ -257,7 +264,7 @@ class CustomQueue extends VerySimpleModel {
                     $core[$path] = $all[$path];
 
         // Add others from current configuration
-        foreach ($this->getCriteria() as $C) {
+        foreach ($criteria ?: $this->getCriteria() as $C) {
             list($path) = $C;
             if (isset($all[$path]))
                 $core[$path] = $all[$path];
@@ -271,6 +278,27 @@ class CustomQueue extends VerySimpleModel {
         return $core;
     }
 
+    /**
+    * Fetch all supported ORM fields filterable by this search object.
+    */
+    function getSupportedFilters() {
+        return static::getFilterableFields($this->getRoot());
+    }
+
+
+    /**
+     * Get get supplemental matches for public queues.
+     *
+     */
+
+    function getSupplementalMatches() {
+        return array();
+    }
+
+    function getSupplementalCriteria() {
+        return array();
+    }
+
     /**
      * Fetch all supported ORM fields searchable by this search object. The
      * returned list represents searchable fields, keyed by the ORM path.
@@ -376,6 +404,20 @@ class CustomQueue extends VerySimpleModel {
         return $fields;
     }
 
+  /**
+     * Fetch all searchable fileds, for the base object  which support quick filters.
+     */
+    function getFilterableFields($object) {
+        $filters = array();
+        foreach (static::getSearchableFields($object) as $p => $f) {
+            list($label, $field) = $f;
+            if ($field && $field->supportsQuickFilter())
+                $filters[$p] = $f;
+        }
+
+        return $filters;
+    }
+
     /**
      * Fetch the FormField instances used when for configuring a searchable
      * field in the user interface. This is the glue between a field
@@ -577,6 +619,10 @@ class CustomQueue extends VerySimpleModel {
         return $fields;
     }
 
+    function getStandardColumns() {
+        return $this->getColumns();
+    }
+
     function getColumns($use_template=false) {
         if ($this->columns_id
             && ($q = CustomQueue::lookup($this->columns_id))
@@ -821,6 +867,7 @@ class CustomQueue extends VerySimpleModel {
      * array retrieved in ::getSearchFields()
      */
     function describeField($info, $name=false) {
+        $name = $name ?: $info['field']->get('label');
         return $info['field']->describeSearch($info['method'], $info['value'], $name);
     }
 
@@ -865,17 +912,25 @@ class CustomQueue extends VerySimpleModel {
     }
 
     function checkAccess(Staff $agent) {
-        return $agent->getId() == $this->staff_id
-            || $this->hasFlag(self::FLAG_PUBLIC);
+        return $this->isPublic() || $this->checkOwnership($agent);
+    }
+
+    function checkOwnership(Staff $agent) {
+
+        return ($agent->getId() == $this->staff_id &&
+                !$this->isAQueue());
+    }
+
+    function isOwner(Staff $agent) {
+        return $agent && $this->isPrivate() && $this->checkOwnership($agent);
     }
 
     function ignoreVisibilityConstraints(Staff $agent) {
         // For saved searches (not queues), some staff can have a permission to
         // see all records
-        return ($this->isPrivate()
-                && $this->checkAccess($agent)
-                && !$this->isASubQueue()
-                && $agent->hasPerm(SearchBackend::PERM_EVERYTHING));
+        return (!$this->isASubQueue()
+                && $this->isOwner($agent)
+                && $agent->canSearchEverything());
     }
 
     function inheritCriteria() {
@@ -886,6 +941,10 @@ class CustomQueue extends VerySimpleModel {
         return $this->hasFlag(self::FLAG_INHERIT_COLUMNS);
     }
 
+    function useStandardColumns() {
+        return !count($this->columns);
+    }
+
     function inheritExport() {
         return ($this->hasFlag(self::FLAG_INHERIT_EXPORT) ||
                 !count($this->exports));
@@ -924,7 +983,12 @@ class CustomQueue extends VerySimpleModel {
     }
 
     function isPrivate() {
-        return !$this->isAQueue() && !$this->hasFlag(self::FLAG_PUBLIC);
+        return !$this->isAQueue() && !$this->isPublic() &&
+            $this->staff_id;
+    }
+
+    function isPublic() {
+        return $this->hasFlag(self::FLAG_PUBLIC);
     }
 
     protected function hasFlag($flag) {
@@ -1003,18 +1067,19 @@ class CustomQueue extends VerySimpleModel {
     }
 
     function update($vars, &$errors=array()) {
+
         // Set basic search information
-        if (!$vars['name'])
-            $errors['name'] = __('A title is required');
+        if (!$vars['queue-name'])
+            $errors['queue-name'] = __('A title is required');
         elseif (($q=CustomQueue::lookup(array(
-                        'title' => $vars['name'],
+                        'title' => $vars['queue-name'],
                         'parent_id' => $vars['parent_id'] ?: 0,
                         'staff_id'  => $this->staff_id)))
                 && $q->getId() != $this->id
                 )
-            $errors['name'] = __('Saved queue with same name exists');
+            $errors['queue-name'] = __('Saved queue with same name exists');
 
-        $this->title = $vars['name'];
+        $this->title = $vars['queue-name'];
         $this->parent_id = @$vars['parent_id'] ?: 0;
         if ($this->parent_id && !$this->parent)
             $errors['parent_id'] = __('Select a valid queue');
@@ -1046,7 +1111,7 @@ class CustomQueue extends VerySimpleModel {
         $this->setFlag(self::FLAG_INHERIT_CRITERIA,
             $this->parent_id > 0 && isset($vars['inherit']));
         $this->setFlag(self::FLAG_INHERIT_COLUMNS,
-            $this->parent_id > 0 && isset($vars['inherit-columns']));
+            isset($vars['inherit-columns']));
         $this->setFlag(self::FLAG_INHERIT_EXPORT,
             $this->parent_id > 0 && isset($vars['inherit-exports']));
         $this->setFlag(self::FLAG_INHERIT_SORTING,
@@ -1057,37 +1122,17 @@ class CustomQueue extends VerySimpleModel {
             // No columns -- imply column inheritance
             $this->setFlag(self::FLAG_INHERIT_COLUMNS);
         }
-        if (isset($vars['columns']) && !$this->hasFlag(self::FLAG_INHERIT_COLUMNS)) {
-            $new = $vars['columns'];
-            $order = array_keys($new);
-            foreach ($this->columns as $col) {
-                $key = $col->column_id;
-                if (!isset($vars['columns'][$key])) {
-                    $this->columns->remove($col);
-                    continue;
-                }
-                $info = $vars['columns'][$key];
-                $col->set('sort', array_search($key, $order));
-                $col->set('heading', $info['heading']);
-                $col->set('width', $info['width']);
-                $col->setSortable($info['sortable']);
-                unset($new[$key]);
-            }
-            // Add new columns
-            foreach ($new as $info) {
-                $glue = new QueueColumnGlue(array(
-                    'column_id' => $info['column_id'],
-                    'sort' => array_search($info['column_id'], $order),
-                    'heading' => $info['heading'],
-                    'width' => $info['width'] ?: 100,
-                    'bits' => $info['sortable'] ?  QueueColumn::FLAG_SORTABLE : 0,
-                ));
-                $glue->queue = $this;
-                $this->columns->add(
-                    QueueColumn::lookup($info['column_id']), $glue);
-            }
-            // Re-sort the in-memory columns array
-            $this->columns->sort(function($c) { return $c->sort; });
+
+
+        if ($this->getId()
+                && isset($vars['columns'])
+                && !$this->hasFlag(self::FLAG_INHERIT_COLUMNS)) {
+
+
+            if ($this->columns->update($vars['columns'], $errors, array(
+                                'queue_id' => $this->getId(),
+                                'staff_id' => $this->staff_id)))
+                $this->columns->reset();
         }
 
         // Update export fields for the queue
@@ -1237,13 +1282,10 @@ class CustomQueue extends VerySimpleModel {
 
 
     static function create($vars=false) {
-        global $thisstaff;
 
         $queue = new static($vars);
         $queue->created = SqlFunction::NOW();
         $queue->setFlag(self::FLAG_QUEUE);
-        if ($thisstaff)
-            $queue->staff_id = $thisstaff->getId();
 
         return $queue;
     }
@@ -2175,6 +2217,71 @@ extends VerySimpleModel {
     }
 }
 
+
+class QueueConfig
+extends VerySimpleModel {
+    static $meta = array(
+        'table' => QUEUE_CONFIG_TABLE,
+        'pk' => array('queue_id', 'staff_id'),
+        'joins' => array(
+            'queue' => array(
+                'constraint' => array(
+                    'queue_id' => 'CustomQueue.id'),
+            ),
+            'staff' => array(
+                'constraint' => array(
+                    'staff_id' => 'Staff.staff_id',
+                )
+            ),
+            'columns' => array(
+                'reverse' => 'QueueColumnGlue.config',
+                'constrain' => array('staff_id' =>'QueueColumnGlue.staff_id'),
+                'broker' => 'QueueColumnListBroker',
+            ),
+        ),
+    );
+
+    function getSettings() {
+        return JsonDataParser::decode($this->setting);
+    }
+
+
+    function update($vars, &$errors) {
+
+        // settings of interest
+        $setting = array(
+                'sort_id' => (int) $vars['sort_id'],
+                'filter' => $vars['filter'],
+                'inherit-columns' => isset($vars['inherit-columns']),
+                'criteria' => $vars['criteria'] ?: array(),
+                );
+
+        if (!$setting['inherit-columns'] && $vars['columns']) {
+            if (!$this->columns->update($vars['columns'], $errors, array(
+                                'queue_id' => $this->queue_id,
+                                'staff_id' => $this->staff_id)))
+                $setting['inherit-columns'] = true;
+            $this->columns->reset();
+        }
+
+        $this->setting =  JsonDataEncoder::encode($setting);
+
+        return $this->save();
+    }
+
+    function save($refetch=false) {
+        if ($this->dirty)
+            $this->updated = SqlFunction::NOW();
+        return parent::save($refetch || $this->dirty);
+    }
+
+    static function create($vars=false) {
+        $inst = new static($vars);
+        return $inst;
+    }
+}
+
+
 class QueueExport
 extends VerySimpleModel {
     static $meta = array(
@@ -2212,16 +2319,23 @@ class QueueColumnGlue
 extends VerySimpleModel {
     static $meta = array(
         'table' => QUEUE_COLUMN_TABLE,
-        'pk' => array('queue_id', 'column_id'),
+        'pk' => array('queue_id', 'staff_id', 'column_id'),
         'joins' => array(
             'column' => array(
                 'constraint' => array('column_id' => 'QueueColumn.id'),
             ),
             'queue' => array(
-                'constraint' => array('queue_id' => 'CustomQueue.id'),
+                'constraint' => array(
+                    'queue_id' => 'CustomQueue.id',
+                    'staff_id' => 'CustomQueue.staff_id'),
+            ),
+            'config' => array(
+                'constraint' => array(
+                    'queue_id' => 'QueueConfig.queue_id',
+                    'staff_id' => 'QueueConfig.staff_id'),
             ),
         ),
-        'select_related' => array('column', 'queue'),
+        'select_related' => array('column'),
         'ordering' => array('sort'),
     );
 }
@@ -2253,6 +2367,44 @@ extends InstrumentedList {
         parent::add($anno, false);
         return $anno;
     }
+
+    function update($columns, &$errors, $options=array()) {
+
+
+        $new = $columns;
+        $order = array_keys($new);
+        foreach ($this as $col) {
+            $key = $col->column_id;
+            if (!isset($columns[$key])) {
+                $this->remove($col);
+                continue;
+            }
+            $info = $columns[$key];
+            $col->set('sort', array_search($key, $order));
+            $col->set('heading', $info['heading']);
+            $col->set('width', $info['width']);
+            $col->setSortable($info['sortable']);
+            unset($new[$key]);
+        }
+        // Add new columns
+        foreach ($new as $info) {
+            $glue = new QueueColumnGlue(array(
+                'staff_id' => $options['staff_id'] ?: 0 ,
+                'queue_id' => $options['queue_id'] ?: 0,
+                'column_id' => $info['column_id'],
+                'sort' => array_search($info['column_id'], $order),
+                'heading' => $info['heading'],
+                'width' => $info['width'] ?: 100,
+                'bits' => $info['sortable'] ?  QueueColumn::FLAG_SORTABLE : 0,
+            ));
+
+            $this->add(QueueColumn::lookup($info['column_id']), $glue);
+        }
+        // Re-sort the in-memory columns array
+        $this->sort(function($c) { return $c->sort; });
+
+        return $this->saveAll();
+    }
 }
 
 class QueueSort
diff --git a/include/class.search.php b/include/class.search.php
index f1d1510de882d8c47169f0af106f01c79dfdf98c..8c5a7c945413cd5355cd525d89dffdf77f028339 100644
--- a/include/class.search.php
+++ b/include/class.search.php
@@ -646,14 +646,29 @@ MysqlSearchBackend::register();
 // Saved search system
 
 /**
- * A special case of the custom queues used to represent an advanced search.
+ * Custom Queue truly represent a saved advanced search.
  */
-class SavedSearch extends CustomQueue {
+class SavedQueue extends CustomQueue {
     // Override the ORM relationship to force no children
     private $children = false;
+    private $_config;
+    private $_criteria;
+    private $_columns;
+    private $_settings;
+    private $_form;
 
-    function isSaved() {
-        return true;
+
+
+    function __onload() {
+        global $thisstaff;
+
+        // Load custom settings for this staff
+        if ($thisstaff) {
+            $this->_config = QueueConfig::lookup(array(
+                         'queue_id' => $this->getId(),
+                         'staff_id' => $thisstaff->getId())
+                    );
+        }
     }
 
     static function forStaff(Staff $agent) {
@@ -664,14 +679,216 @@ class SavedSearch extends CustomQueue {
         ->exclude(array('flags__hasbit'=>self::FLAG_QUEUE));
     }
 
+    private function getSettings() {
+        if (!isset($this->_settings)) {
+            $this->_settings = array();
+            if ($this->_config)
+                $this->_settings = $this->_config->getSettings();
+        }
+
+        return  $this->_settings;
+    }
+
+    private function getCustomColumns() {
+
+        if (!isset($this->_columns)) {
+            $this->_columns = array();
+            if ($this->_config
+                    && $this->_config->columns->count())
+                $this->_columns = $this->_config->columns;
+        }
+
+        return $this->_columns;
+    }
+
+    /**
+     * Fetch an AdvancedSearchForm instance for use in displaying or
+     * configuring this search in the user interface.
+     *
+     */
+    function getForm($source=null, $searchable=array()) {
+        global $thisstaff;
+
+        if (!$this->isAQueue())
+            $searchable =  $this->getCurrentSearchFields($source,
+                     parent::getCriteria());
+        else // Only allow supplemental matches.
+            $searchable = array_intersect_key($this->getCurrentSearchFields($source),
+                    $this->getSupplementalMatches());
+
+        return parent::getForm($source, $searchable);
+    }
+
+   /**
+     * Get get supplemental matches for public queues.
+     *
+     */
+    function getSupplementalMatches() {
+        // Target flags
+        $flags = array('isoverdue', 'isassigned', 'isreopened', 'isanswered');
+        $current = array();
+        // Check for closed state - whih disables above flags
+        foreach (parent::getCriteria() as $c) {
+            if (!strcasecmp($c[0], 'status__state')
+                    && isset($c[2]['closed']))
+                return array();
+
+            $current[] = $c[0];
+        }
+
+        // Filter out fields already in criteria
+        $matches = array_intersect_key($this->getSupportedMatches(),
+                array_flip(array_diff($flags, $current)));
+
+        return $matches;
+    }
+
+    function criteriaRequired() {
+        return !$this->isAQueue();
+    }
+
+    function describeCriteria($criteria=false){
+        $criteria = $criteria ?: parent::getCriteria();
+        return parent::describeCriteria($criteria);
+    }
+
+    function getCriteria($include_parent=true) {
+
+        if (!isset($this->_criteria)) {
+            $this->getSettings();
+            $this->_criteria = $this->_settings['criteria'] ?: array();
+        }
+
+        $criteria = $this->_criteria;
+        if ($include_parent)
+            $criteria = array_merge($criteria,
+                    parent::getCriteria($include_parent));
+
+
+        return $criteria;
+    }
+
+    function getSupplementalCriteria() {
+        return $this->getCriteria(false);
+    }
+
+    function useStandardColumns() {
+
+        $this->getSettings();
+        if ($this->getCustomColumns()
+                && isset($this->_settings['inherit-columns']))
+            return $this->_settings['inherit-columns'];
+
+        // owner?? edit away.
+        if ($this->_config
+                && $this->_config->staff_id == $this->staff_id)
+            return false;
+
+        return parent::useStandardColumns();
+    }
+
+    function getStandardColumns() {
+        return parent::getColumns(($this->parent));
+    }
+
+    function getColumns($use_template=false) {
+
+        if (!$this->useStandardColumns() && ($columns=$this->getCustomColumns()))
+            return $columns;
+
+        return parent::getColumns($use_template);
+    }
+
     function update($vars, &$errors=array()) {
-        if (!parent::update($vars, $errors))
+        global $thisstaff;
+
+        if (!$this->checkAccess($thisstaff))
             return false;
 
-        // Personal queues _always_ inherit from their parent
-        $this->setFlag(self::FLAG_INHERIT_CRITERIA, $this->parent_id > 0);
+        if ($this->checkOwnership($thisstaff)) {
+            // Owner of the queue - can update everything
+            if (!parent::update($vars, $errors))
+                return false;
+
+            // Personal queues _always_ inherit from their parent
+            $this->setFlag(self::FLAG_INHERIT_CRITERIA, $this->parent_id >
+                    0);
 
-        return count($errors) === 0;
+            return true;
+        }
+
+        // Agent's config for public queue.
+        if (!$this->_config)
+            $this->_config = QueueConfig::create(array(
+                        'queue_id' => $this->getId(),
+                        'staff_id' => $thisstaff->getId()));
+
+        //  Validate & isolate supplemental criteria (if any)
+        $vars['criteria'] = array();
+        if (isset($vars['fields'])) {
+           $form = $this->getForm($vars, $thisstaff);
+            if ($form->isValid()) {
+                $criteria = self::isolateCriteria($form->getClean(),
+                        $this->getRoot());
+                $allowed = $this->getSupplementalMatches();
+                foreach ($criteria as $k => $c)
+                    if (!isset($allowed[$c[0]]))
+                        unset($criteria[$k]);
+
+                $vars['criteria'] = $criteria ?: array();
+            } else {
+                $errors['criteria'] = __('Validation errors exist on supplimental criteria');
+            }
+        }
+
+        if (!$errors && $this->_config->update($vars, $errors))
+            $this->_settings = $this->_criteria = null;
+
+        return (!$errors);
+    }
+
+    static function ticketsCount($agent, $criteria=array(),
+            $prefix='') {
+
+        if (!$agent instanceof Staff)
+            return array();
+
+        $queues = SavedQueue::objects()
+            ->filter(Q::any(array(
+                'flags__hasbit' => CustomQueue::FLAG_PUBLIC,
+                'staff_id' => $agent->getId(),
+            )));
+
+        if ($criteria)
+            $queues->filter($criteria);
+
+        $query = Ticket::objects();
+        // Apply tickets visibility for the agent
+        $query = $agent->applyVisibility($query);
+        // Aggregate constraints
+        foreach ($queues as $queue) {
+            $Q = $queue->getBasicQuery();
+            $expr = SqlCase::N()->when(new SqlExpr(new Q($Q->constraints)), new SqlField('ticket_id'));
+            $query->aggregate(array(
+                "$prefix{$queue->id}" => SqlAggregate::COUNT($expr, true)
+            ));
+        }
+
+        return $query->values()->one();
+    }
+
+    static function lookup($criteria) {
+        $queue = parent::lookup($criteria);
+        // Annoted cusom settings (if any)
+        if (($c=$queue->_config)) {
+            $queue->_settings = $c->getSettings() ?: array();
+            $queue = AnnotatedModel::wrap($queue,
+                        array_intersect_key($queue->_settings,
+                            array_flip(array('sort_id', 'filter'))));
+            $queue->_config = $c;
+        }
+
+        return $queue;
     }
 
     static function create($vars=false) {
@@ -681,6 +898,13 @@ class SavedSearch extends CustomQueue {
     }
 }
 
+class SavedSearch extends SavedQueue {
+
+    function isSaved() {
+        return (!$this->__new__);
+    }
+}
+
 class AdhocSearch
 extends SavedSearch {
 
@@ -717,17 +941,34 @@ extends SavedSearch {
     }
 }
 
+// AdvacedSearchForm
 class AdvancedSearchForm extends SimpleForm {
     static $id = 1337;
+
+    function getNumFieldsSelected() {
+        $selected = 0;
+        foreach ($this->getFields() as $F) {
+            if (substr($F->get('name'), -7) == '+search'
+                    && $F->getClean())
+                $selected += 1;
+            // Consider keyword searches
+            elseif ($F->get('name') == ':keywords'
+                    && $F->getClean())
+                $selected += 1;
+        }
+        return $selected;
+    }
 }
 
 // Advanced search special fields
 
 class AdvancedSearchSelectionField extends ChoiceField {
 
-    function getSearchQ($method, $value, $name=false) {
-
+    function hasIdValue() {
+        return false;
+    }
 
+    function getSearchQ($method, $value, $name=false) {
         switch ($method) {
             case 'includes':
             case '!includes':
@@ -741,6 +982,13 @@ class AdvancedSearchSelectionField extends ChoiceField {
                     $Q->negate();
                 return $Q;
                 break;
+            // osTicket commonly uses `0` to represent an unset state, so
+            // the set and unset checks need to check for both not null and
+            // nonzero
+            case 'nset':
+                return new Q([$name => 0]);
+            case 'set':
+                return Q::not([$name => 0]);
             default:
                 return parent::getSearchQ($method, $value, $name);
         }
@@ -903,12 +1151,45 @@ class AssigneeChoiceField extends ChoiceField {
     }
 
     function applyOrderBy($query, $reverse=false, $name=false) {
+        global $cfg;
+
         $reverse = $reverse ? '-' : '';
-        return $query->order_by("{$reverse}staff__firstname",
-            "{$reverse}staff__lastname", "{$reverse}team__name");
+        switch ($cfg->getAgentNameFormat()) {
+        case 'last':
+        case 'lastfirst':
+        case 'legal':
+            $query->order_by("{$reverse}staff__lastname",
+                "{$reverse}staff__firstname",  "{$reverse}team__name");
+            break;
+        default:
+            $query->order_by("{$reverse}staff__firstname",
+                "{$reverse}staff__lastname", "{$reverse}team__name");
+        }
+
+        return $query;
     }
 }
 
+class AssignedField extends AssigneeChoiceField {
+
+    function getSearchMethods() {
+        return array(
+            'assigned' =>   __('assigned'),
+            '!assigned' =>  __('unassigned'),
+        );
+    }
+
+    function addToQuery($query, $name=false) {
+        return $query->values('staff_id', 'team_id');
+    }
+
+    function from_query($row, $name=false) {
+        return ($row['staff_id'] || $row['staff_id'])
+            ? __('Yes') : __('No');
+    }
+
+}
+
 /**
  * Simple trait which changes the SQL for "has a value" and "does not have a
  * value" to check for zero or non-zero. Useful for not nullable fields.
@@ -933,7 +1214,7 @@ class AgentSelectionField extends AdvancedSearchSelectionField {
     use ZeroMeansUnset;
 
     function getChoices($verbose=false) {
-        return Staff::getStaffMembers();
+        return array('M' => __('Me')) + Staff::getStaffMembers();
     }
 
     function toString($value) {
@@ -947,6 +1228,18 @@ class AgentSelectionField extends AdvancedSearchSelectionField {
             parent::toString($value);
     }
 
+    function getSearchQ($method, $value, $name=false) {
+        global $thisstaff;
+        // unpack me
+        if (isset($value['M']) && $thisstaff) {
+            $value[$thisstaff->getId()] = $thisstaff->getName();
+            unset($value['M']);
+        }
+
+        return parent::getSearchQ($method, $value, $name);
+    }
+
+
     function applyOrderBy($query, $reverse=false, $name=false) {
         global $cfg;
 
@@ -978,11 +1271,23 @@ class DepartmentManagerSelectionField extends AgentSelectionField {
     }
 }
 
-class TeamSelectionField extends ChoiceField {
-    use ZeroMeansUnset;
+class TeamSelectionField extends AdvancedSearchSelectionField {
 
     function getChoices($verbose=false) {
-        return Team::getTeams();
+        return array('T' => __('One of my teams')) + Team::getTeams();
+    }
+
+    function getSearchQ($method, $value, $name=false) {
+        global $thisstaff;
+
+        // Unpack my teams
+        if (isset($value['T']) && $thisstaff
+                && ($teams = $thisstaff->getTeams())) {
+            unset($value['T']);
+            $value = $value + array_flip($teams);
+        }
+
+        return parent::getSearchQ($method, $value, $name);
     }
 
     function applyOrderBy($query, $reverse=false, $name=false) {
diff --git a/include/class.staff.php b/include/class.staff.php
index d3676afb5d71a3783cb87a3332d2a30f28cfdca2..0c35a0c1c4b5fb33f9b327a811d68d4aa624e4d4 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -359,7 +359,7 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable {
             $depts = array();
             if (($res=db_query($sql)) && db_num_rows($res)) {
                 while(list($id)=db_fetch_row($res))
-                    $depts[] = $id;
+                    $depts[] = (int) $id;
             }
 
             /* ORM method — about 2.0ms slower
@@ -491,6 +491,10 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable {
         return false;
     }
 
+    function canSearchEverything() {
+        return $this->hasPerm(SearchBackend::PERM_EVERYTHING);
+    }
+
     function canManageTickets() {
         return $this->hasPerm(Ticket::PERM_DELETE, false)
                 || $this->hasPerm(Ticket::PERM_TRANSFER, false)
@@ -556,7 +560,7 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable {
         if (!isset($this->_teams)) {
             $this->_teams = array();
             foreach ($this->teams as $team)
-                 $this->_teams[] = $team->team_id;
+                 $this->_teams[] = (int) $team->team_id;
         }
 
         return $this->_teams;
@@ -588,6 +592,10 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable {
         return $visibility;
     }
 
+    function applyVisibility($query) {
+        return $query->filter($this->getTicketsVisibility());
+    }
+
     /* stats */
     function resetStats() {
         $this->stats = array();
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 3d7e148ca7040e29302d943d5fb3308dddc89c88..a1147c2cbb29115766bfe4279cc9d98aef31c97f 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -2084,10 +2084,14 @@ implements RestrictedAccess, Threadable, Searchable {
                 'label' => __('Create Date'),
                 'configuration' => array('fromdb' => true),
             )),
-            'est_duedate' => new DatetimeField(array(
+            'duedate' => new DatetimeField(array(
                 'label' => __('Due Date'),
                 'configuration' => array('fromdb' => true),
             )),
+            'est_duedate' => new DatetimeField(array(
+                'label' => __('SLA Due Date'),
+                'configuration' => array('fromdb' => true),
+            )),
             'reopened' => new DatetimeField(array(
                 'label' => __('Reopen Date'),
                 'configuration' => array('fromdb' => true),
@@ -2120,9 +2124,20 @@ implements RestrictedAccess, Threadable, Searchable {
             )),
             'isoverdue' => new BooleanField(array(
                 'label' => __('Overdue'),
+                'descsearchmethods' => array(
+                    'set' => '%s',
+                    'nset' => 'Not %s'
+                    ),
             )),
             'isanswered' => new BooleanField(array(
                 'label' => __('Answered'),
+                'descsearchmethods' => array(
+                    'set' => '%s',
+                    'nset' => 'Not %s'
+                    ),
+            )),
+            'isassigned' => new AssignedField(array(
+                        'label' => __('Assigned'),
             )),
             'ip_address' => new TextboxField(array(
                 'label' => __('IP Address'),
diff --git a/include/i18n/en_US/queue.yaml b/include/i18n/en_US/queue.yaml
index 0d572c5c7d3ea24779aceaa3b6fc3ae07312ff2b..ab2b1a4bbb3453e14c7843b81a75d65751b94d9e 100644
--- a/include/i18n/en_US/queue.yaml
+++ b/include/i18n/en_US/queue.yaml
@@ -75,7 +75,7 @@
   parent_id: 1
   flags: 0x03
   root: T
-  sort: 4
+  sort: 2
   config: '[["isanswered","set",null]]'
   columns:
     - column_id: 1
@@ -114,8 +114,6 @@
     - sort_id: 3
     - sort_id: 4
 
-
-
 - id: 3
   title: My Tickets
   parent_id: 0
@@ -205,55 +203,12 @@
     - sort_id: 1
     - sort_id: 2
 
-- title: Unassigned
-  parent_id: 1
-  flags: 0x2b
-  root: T
-  sort: 1
-  config: '[["assignee","!assigned",null]]'
-  columns:
-    - column_id: 1
-      bits: 1
-      sort: 1
-      sort: 1
-      width: 100
-      heading: Ticket
-    - column_id: 10
-      bits: 1
-      sort: 1
-      sort: 2
-      width: 150
-      heading: Last Update
-    - column_id: 3
-      bits: 1
-      sort: 1
-      sort: 3
-      width: 300
-      heading: Subject
-    - column_id: 4
-      bits: 1
-      sort: 1
-      sort: 4
-      width: 185
-      heading: From
-    - column_id: 5
-      bits: 1
-      sort: 1
-      sort: 5
-      width: 85
-      heading: Priority
-    - column_id: 11
-      bits: 1
-      sort: 1
-      sort: 6
-      width: 160
-      heading: Department
-
-- title: Assigned
+- id: 5
+  title: Assigned
   parent_id: 1
   flags: 0x03
   root: T
-  sort: 2
+  sort: 3
   config: '[["assignee","assigned",null]]'
   columns:
     - column_id: 1
@@ -287,11 +242,12 @@
       width: 160
       heading: Assigned To
 
-- title: Overdue
+- id: 6
+  title: Overdue
   parent_id: 1
   flags: 0x2b
   root: T
-  sort: 3
+  sort: 4
   sort_id: 4
   config: '[["isoverdue","set",null]]'
   columns:
@@ -300,7 +256,7 @@
       sort: 1
       width: 100
       heading: Ticket
-    - column_id: 10
+    - column_id: 9
       bits: 1
       sort: 1
       sort: 9
@@ -330,18 +286,3 @@
       sort: 6
       width: 160
       heading: Assigned To
-
-- title: Personal Tickets
-  parent_id: 3
-  flags: 0x2b
-  root: T
-  sort: 1
-  config: '{"criteria":[["assignee","includes",{"M":"Me"}]]}'
-
-- title: Teams Tickets
-  parent_id: 3
-  flags: 0x2b
-  root: T
-  sort: 2
-  config: '{"criteria":[["team_id","set",null]],"conditions":[]}'
-  filter: team_id
diff --git a/include/i18n/en_US/queue_column.yaml b/include/i18n/en_US/queue_column.yaml
index 1c1d011f5df1cef9b1cc08eb3f002c7124778113..6f7419a4af0e0074293b957b07f813668d1889e4 100644
--- a/include/i18n/en_US/queue_column.yaml
+++ b/include/i18n/en_US/queue_column.yaml
@@ -92,7 +92,8 @@
 
 - id: 9
   name: "Due Date"
-  primary: "est_duedate"
+  primary: "duedate"
+  secondary: "est_duedate"
   filter: "date:human"
   truncate: "wrap"
   annotations: "[]"
diff --git a/include/staff/queue.inc.php b/include/staff/queue.inc.php
index bf41bd1a48b42204c95fbec0b7fda987229c032a..8506fbee9d1ce3d78b429fe74c969f7f2771f158 100644
--- a/include/staff/queue.inc.php
+++ b/include/staff/queue.inc.php
@@ -57,11 +57,11 @@ else {
     <table class="table">
       <td style="width:60%; vertical-align:top">
         <div><strong><?php echo __('Queue Name'); ?>:</strong></div>
-        <input type="text" name="name" value="<?php
+        <input type="text" name="queue-name" value="<?php
           echo Format::htmlchars($queue->getName()); ?>"
           style="width:100%" />
-
         <br/>
+        <div class="error"><?php echo $errors['queue-name']; ?></div>
         <br/>
         <div><strong><?php echo __("Queue Search Criteria"); ?></strong></div>
         <label class="checkbox" style="line-height:1.3em">
@@ -120,10 +120,8 @@ else {
             if ($queue->parent
                 && ($qf = $queue->parent->getQuickFilterField()))
                 echo sprintf(' (%s)', $qf->getLabel()); ?> —</option>
-<?php foreach (CustomQueue::getSearchableFields('Ticket') as $path=>$f) {
+<?php foreach ($queue->getSupportedFilters() as $path => $f) {
         list($label, $field) = $f;
-        if (!$field->supportsQuickFilter())
-          continue;
 ?>
           <option value="<?php echo $path; ?>"
             <?php if ($path == $queue->filter) echo 'selected="selected"'; ?>
@@ -314,8 +312,8 @@ var Q = setInterval(function() {
 }();
 </script>
         </table>
-    </div>    
-    
+    </div>
+
     <div class="hidden tab_content" id="preview-tab">
     <div id="preview">
     </div>
@@ -339,7 +337,7 @@ var Q = setInterval(function() {
 
   <div class="hidden tab_content" id="conditions-tab">
     <div style="margin-bottom: 15px"><?php echo __("Conditions are used to change the view of the data in a row based on some conditions of the data. For instance, a column might be shown bold if some condition is met.");
-      ?> <?php echo __("These conditions apply to an entire row in the queue."); 
+      ?> <?php echo __("These conditions apply to an entire row in the queue.");
     ?></div>
     <div class="conditions">
 <?php
diff --git a/include/staff/templates/advanced-search-criteria.tmpl.php b/include/staff/templates/advanced-search-criteria.tmpl.php
index 136c7d139bb7a35d382757fe2e534230f79d997a..9348cf79be9a81e3cb762f1bcaf96604acedf437 100644
--- a/include/staff/templates/advanced-search-criteria.tmpl.php
+++ b/include/staff/templates/advanced-search-criteria.tmpl.php
@@ -1,9 +1,29 @@
 <?php
-foreach ($form->errors(true) ?: array() as $message) {
-    ?><div class="error-banner"><?php echo $message;?></div><?php
+// Display errors if any
+foreach ($form->errors(true) ?: array() as $message)
+    echo sprintf('<div class="error-banner">%s</div>',
+            Format::htmlchars($message));
+// Current search fields.
+$info = $search->getSearchFields($form) ?: array();
+if (($search instanceof SavedQueue) && !$search->checkOwnership($thisstaff)) {
+    $matches = $search->getSupplementalMatches();
+    // Uneditable core criteria for the queue
+    echo '<div class="faded">'.  nl2br(Format::htmlchars($search->describeCriteria())).
+                    '</div><br>';
+    // Show any supplemental filters
+    if ($matches  && count($info)) {
+        ?>
+        <div id="ticket-flags"
+            style="padding:5px; border-top: 1px dotted #777;">
+            <strong><i class="icon-caret-down"></i>&nbsp;<?php
+                echo __('Supplemental Filters'); ?></strong>
+        </div>
+<?php
+    }
+} else {
+    $matches = $search->getSupportedMatches();
 }
 
-$info = $search->getSearchFields($form);
 foreach (array_keys($info) as $F) {
     ?><input type="hidden" name="fields[]" value="<?php echo $F; ?>"/><?php
 }
@@ -51,8 +71,7 @@ foreach ($form->getFields() as $name=>$field) {
     $this.closest('.adv-search-field-container').find('.adv-search-field-body').slideDown('fast');
     $this.find('span.faded').hide();
     $this.find('i').removeClass('icon-caret-right').addClass('icon-caret-down');
-    return false;
-"><i class="icon-caret-right"></i>
+    return false; "><i class="icon-caret-right"></i>
             <span class="faded"><?php echo $search->describeField($info[$name]); ?></span>
             </a>
             </span>
@@ -62,21 +81,20 @@ foreach ($form->getFields() as $name=>$field) {
         } ?>
     </fieldset>
     <?php if ($name[0] == ':' && substr($name, -7) == '+search') {
-        list($N,) = explode('+', $name, 2);
-?>
+        list($N,) = explode('+', $name, 2); ?>
     <input type="hidden" name="fields[]" value="<?php echo $N; ?>"/>
     <?php }
 }
 if (!$first_field)
     echo '</div></div>';
-?>
+
+if ($matches && is_array($matches)) { ?>
 <div id="extra-fields"></div>
 <hr/>
 <i class="icon-plus-sign"></i>
 <select id="search-add-new-field" name="new-field" style="max-width: 300px;">
     <option value="">— <?php echo __('Add Other Field'); ?> —</option>
 <?php
-if (is_array($matches)) {
 foreach ($matches as $path => $F) {
     # Skip fields already listed above the drop-down
     if (isset($already_listed[$path]))
@@ -86,7 +104,7 @@ foreach ($matches as $path => $F) {
         if (isset($state[$path])) echo 'disabled="disabled"';
         ?>><?php echo $label; ?></option>
 <?php }
-} ?>
+?>
 </select>
 <script>
 $(function() {
@@ -100,9 +118,12 @@ $(function() {
         if (!json.success)
           return false;
         $(that).find(':selected').prop('disabled', true);
+        $(that).find('option:eq("")').prop('selected', true);
         $('#extra-fields').append($(json.html));
       }
     });
   });
 });
 </script>
+<?php
+} ?>
diff --git a/include/staff/templates/advanced-search.tmpl.php b/include/staff/templates/advanced-search.tmpl.php
index 71d2deedcb0314a1dd4355bad643fb42a68d363d..0fe2b99dcb420a7d6297e18e8c8426afbed7b727 100644
--- a/include/staff/templates/advanced-search.tmpl.php
+++ b/include/staff/templates/advanced-search.tmpl.php
@@ -1,11 +1,15 @@
 <?php
+global $thisstaff;
+
 $parent_id = $_REQUEST['parent_id'] ?: $search->parent_id;
 if ($parent_id
-    && (!($parent = CustomQueue::lookup($parent_id)))
+    && is_numeric($parent_id)
+    && (!($parent = SavedQueue::lookup($parent_id)))
 ) {
     $parent_id = 0;
 }
 
+$editable = $search->checkOwnership($thisstaff);
 $queues = array();
 foreach (CustomQueue::queues() as  $q)
     $queues[$q->id] = $q->getFullName();
@@ -26,10 +30,21 @@ if ($info['error']) {
     echo sprintf('<p id="msg_warning">%s</p>', $info['warn']);
 } elseif ($info['msg']) {
     echo sprintf('<p id="msg_notice">%s</p>', $info['msg']);
-} ?>
-<form action="#tickets/search" method="post" name="search" id="advsearch"
+}
+
+// Form action
+$action = '#tickets/search';
+if ($search->isSaved() && $search->getId())
+    $action .= sprintf('/%s/save', $search->getId());
+elseif (!$search instanceof AdhocSearch)
+    $action .= '/save';
+?>
+<form action="<?php echo $action; ?>" method="post" name="search" id="advsearch"
     class="<?php echo ($search->isSaved() || $parent) ? 'savedsearch' : 'adhocsearch'; ?>">
   <input type="hidden" name="id" value="<?php echo $search->getId(); ?>">
+<?php
+if ($editable) {
+    ?>
   <div class="flex row">
     <div class="span12">
       <select id="parent" name="parent_id" >
@@ -43,10 +58,16 @@ foreach ($queues as $id => $name) {
       </select>
     </div>
    </div>
+<?php
+} ?>
 <ul class="clean tabs">
     <li class="active"><a href="#criteria"><i class="icon-search"></i> <?php echo __('Criteria'); ?></a></li>
     <li><a href="#columns"><i class="icon-columns"></i> <?php echo __('Columns'); ?></a></li>
-    <li><a href="#fields"><i class="icon-download"></i> <?php echo __('Export'); ?></a></li>
+    <?php
+    if ($search->isSaved()) { ?>
+    <li><a href="#settings"><i class="icon-cog"></i> <?php echo __('Settings'); ?></a></li>
+    <?php
+    } ?>
 </ul>
 
 <div class="tab_content" id="criteria">
@@ -68,51 +89,80 @@ foreach ($queues as $id => $name) {
       </div>
       </div>
       <input type="hidden" name="a" value="search">
-      <?php include STAFFINC_DIR . 'templates/advanced-search-criteria.tmpl.php'; ?>
+     <?php
+        include STAFFINC_DIR . 'templates/advanced-search-criteria.tmpl.php';
+     ?>
     </div>
   </div>
 
 </div>
 
-<div class="tab_content hidden" id="columns" style="overflow-y: auto;
-height:auto;">
+<div class="tab_content hidden" id="columns">
     <?php
     include STAFFINC_DIR . "templates/queue-columns.tmpl.php";
     ?>
 </div>
-<div class="tab_content hidden" id="fields">
+<?php
+if ($search->isSaved()) { ?>
+<div class="tab_content hidden" id="settings">
     <?php
-    include STAFFINC_DIR . "templates/queue-fields.tmpl.php";  ?>
+    include STAFFINC_DIR . "templates/savedqueue-settings.tmpl.php";
+    ?>
 </div>
-   <?php
-   $save = (($parent && !$search->isSaved()) || $errors); ?>
+<?php
+} else { // Not saved.
+    $save = (($parent && !$search->isSaved()) || isset($_POST['queue-name']));
+?>
+<div>
   <div style="margin-top:10px;"><a href="#"
     id="save"><i class="icon-caret-<?php echo $save ? 'down' : 'right';
     ?>"></i>&nbsp;<span><?php echo __('Save Search'); ?></span></a></div>
   <div id="save-changes" class="<?php echo $save ? '' : 'hidden'; ?>" style="padding:5px; border-top: 1px dotted #777;">
-      <div><input name="name" type="text" size="40"
-        value="<?php echo $search->isSaved() ? Format::htmlchars($search->getName()) : ''; ?>"
+      <div><input name="queue-name" type="text" size="40"
+        value="<?php echo Format::htmlchars($search->isSaved() ? $search->getName() :
+        $_POST['queue-name']); ?>"
         placeholder="<?php echo __('Search Title'); ?>">
+        <?php
+        if ($search instanceof AdhocSearch && !$search->isSaved()) { ?>
         <span class="buttons">
-             <button class="button" type="button" name="save"
+             <button class="save button" type="button"  name="save-search"
              value="save"><i class="icon-save"></i>  <?php echo $search->id
              ? __('Save Changes') : __('Save'); ?></button>
         </span>
+        <?php
+        } ?>
         </div>
-      <div class="error" id="name-error"><?php echo Format::htmlchars($errors['name']); ?></div>
+      <div class="error" id="name-error"><?php echo
+      Format::htmlchars($errors['queue-name']); ?></div>
   </div>
+ </div>
+<?php
+} ?>
   <hr/>
  <div>
   <p class="full-width">
     <span class="buttons pull-left">
-        <input type="reset"  id="reset"  value="<?php echo __('Reset'); ?>">
-        <input type="button" name="cancel" class="close"
-        value="<?php echo __('Cancel'); ?>">
+        <input type="button"  name="cancel"  class="close" value="<?php echo __('Cancel'); ?>">
+        <?php
+        if ($search->isSaved()) { ?>
+        <input type="button" name="done" class="done" value="<?php echo
+            __('Done'); ?>" >
+        <?php
+        } ?>
     </span>
     <span class="buttons pull-right">
+      <?php
+      if (!$search instanceof AdhocSearch) { ?>
+      <button class="save button" type="submit" name="save" value="save"
+        id="do_save"><i class="icon-save"></i>
+        <?php echo __('Save'); ?></button>
+      <?php
+      } else { ?>
       <button class="button" type="submit" name="submit" value="search"
         id="do_search"><i class="icon-search"></i>
         <?php echo __('Search'); ?></button>
+      <?php
+      } ?>
     </span>
    </p>
  </div>
@@ -185,32 +235,45 @@ height:auto;">
         return false;
     });
 
-    $('form.savedsearch').on('keyup change paste', 'input, select, textarea', function() {
-       var form = $(this).closest('form');
-       $this = $('#save-changes', form);
-       if ($this.is(":hidden"))
-           $this.fadeIn();
-        $('a#save').find('i').removeClass('icon-caret-right').addClass('icon-caret-down');
-        $('button[name=save]', form).addClass('save pending');
-        $('div.error', form).html('');
+    $('form#advsearch').on('keyup change paste', 'input, select, textarea', function() {
+
+        var form = $(this).closest('form');
+        $this = $('#save-changes', form);
+        $('button.save', form).addClass('save pending');
+        $('div.error, div.error-banner', form).html('').hide();
      });
 
     $(document).on('click', 'form#advsearch input#reset', function(e) {
         var f = $(this).closest('form');
-        $('button[name=save]', f).removeClass('save pending');
+        $('button.save', f).removeClass('save pending');
         $('div#save-changes', f).hide();
     });
 
-    $('button[name=save]').click(function() {
+    $('button[name=save-search]').click(function() {
         var $form = $(this).closest('form');
         var id = parseInt($('input[name=id]', $form).val(), 10) || 0;
-        var action = '#tickets/search';
-        if (id > 0)
-            action = action + '/'+id;
+        var name = $('input[name=queue-name]', $form).val();
+        if (name.length) {
+            var action = '#tickets/search';
+            if (id > 0)
+                action = action + '/'+id;
+            $form.prop('action', action+'/save');
+            $form.submit();
+        } else {
+            $('div#name-error', $form).html('<?php echo __('Name required');
+                    ?>').show();
+        }
 
-        $form.prop('action', action+'/save');
-        $form.submit();
+        return false;
     });
 
+    $('input.done').click(function() {
+        var $form = $(this).closest('form');
+        var id = parseInt($('input[name=id]', $form).val(), 10) || 0;
+        if ($('button.save', $form).hasClass('pending'))
+            alert('Unsaved Changes - save or cancel to discard!');
+        else
+            window.location.href = 'tickets.php?queue='+id;
+    });
 }();
 </script>
diff --git a/include/staff/templates/queue-columns.tmpl.php b/include/staff/templates/queue-columns.tmpl.php
index 233a7c411defb2f853a22d3563502719efa4f262..189ee1b3b67890a99ac55250e1c4c2e1cba0ecd2 100644
--- a/include/staff/templates/queue-columns.tmpl.php
+++ b/include/staff/templates/queue-columns.tmpl.php
@@ -1,3 +1,4 @@
+<div style="overflow-y: auto; height:auto; max-height: 350px;">
 <table class="table">
 <?php
 if ($queue->parent) { ?>
@@ -12,24 +13,22 @@ if ($queue->parent) { ?>
       </td>
     </tr>
   </tbody>
-<?php }
-      // Adhoc Advanced search does not have customizable columns, but saved
-      // ones do
-      elseif ($queue->__new__) { ?>
+<?php } elseif ($queue instanceof SavedQueue) { ?>
   <tbody>
     <tr>
       <td colspan="3">
         <input type="checkbox" name="inherit-columns" <?php
-          if (count($queue->columns) == 0) echo 'checked="checked"';
-          if ($queue instanceof SavedSearch) echo 'disabled="disabled"'; ?>
-          onchange="javascript:$(this).closest('table').find('.if-not-inherited').toggle(!$(this).prop('checked'));" />
+          if ($queue->useStandardColumns()) echo 'checked="checked"';
+          if ($queue instanceof SavedSearch && $queue->__new__) echo 'disabled="disabled"'; ?>
+          onchange="javascript:$(this).closest('table').find('.if-not-inherited').toggle(!$(this).prop('checked'));
+          $(this).closest('table').find('.standard-columns').toggle($(this).prop('checked'));" />
         <?php echo __('Use standard columns'); ?>
         <br /><br />
       </td>
     </tr>
   </tbody>
 <?php }
-$hidden_cols = $queue->inheritColumns() || count($queue->columns) === 0;
+$hidden_cols = $queue->inheritColumns() || $queue->useStandardColumns();
 ?>
   <tbody class="if-not-inherited <?php if ($hidden_cols) echo 'hidden'; ?>">
     <tr class="header">
@@ -92,8 +91,19 @@ $hidden_cols = $queue->inheritColumns() || count($queue->columns) === 0;
       </td>
     </tr>
   </tbody>
+  <tbody class="standard-columns <?php if (!$hidden_cols) echo 'hidden'; ?>">
+    <?php
+    foreach ($queue->getStandardColumns() as $c) { ?>
+    <tr>
+      <td nowrap><?php echo Format::htmlchars($c->heading); ?></td>
+      <td nowrap><?php echo Format::htmlchars($c->name); ?></td>
+      <td>&nbsp;</td>
+    </tr>
+    <?php
+    } ?>
+  </tbody>
 </table>
-
+</div>
 <script>
 +function() {
 var Q = setInterval(function() {
@@ -102,7 +112,10 @@ var Q = setInterval(function() {
   clearInterval(Q);
 
   var addColumn = function(colid, info) {
-    if (!colid) return;
+
+    if (!colid || $('tr#column-'+colid).length)
+        return;
+
     var copy = $('#column-template').clone(),
         name_prefix = 'columns[' + colid + ']';
     info['column_id'] = colid;
@@ -119,7 +132,7 @@ var Q = setInterval(function() {
       $this.attr('name', name_prefix + '[' + name + ']');
     });
     copy.find('span').text(info['name']);
-    copy.attr('id', '').show().insertBefore($('#column-template'));
+    copy.attr('id', 'column-'+colid).show().insertBefore($('#column-template'));
     copy.removeClass('hidden');
     if (info['trans'] !== undefined) {
       var input = copy.find('input[data-translate-tag]')
diff --git a/include/staff/templates/queue-tickets.tmpl.php b/include/staff/templates/queue-tickets.tmpl.php
index fb883ba85178ef417b974949592a7dac737a5783..37d7cced74789b85fd6aa1f6cf6b0dc720eacc30 100644
--- a/include/staff/templates/queue-tickets.tmpl.php
+++ b/include/staff/templates/queue-tickets.tmpl.php
@@ -122,62 +122,37 @@ return false;">
             <div class="pull-left flush-left">
                 <h2><a href="<?php echo $refresh_url; ?>"
                     title="<?php echo __('Refresh'); ?>"><i class="icon-refresh"></i> <?php echo
-                    $queue->getName(); ?></a></h2>
+                    $queue->getName(); ?></a>
+                    <?php
+                    if (($crit=$queue->getSupplementalCriteria()))
+                        echo sprintf('<i class="icon-filter"
+                                data-placement="bottom" data-toggle="tooltip"
+                                title="%s"></i>&nbsp;',
+                                Format::htmlchars($queue->describeCriteria($crit)));
+                    ?>
+                </h2>
             </div>
             <div class="configureQ">
                 <i class="icon-cog"></i>
                 <div class="noclick-dropdown anchor-left">
                     <ul>
-<?php
-if ($queue->isPrivate()) { ?>
                         <li>
                             <a class="no-pjax" href="#"
                               data-dialog="ajax.php/tickets/search/<?php echo
                               urlencode($queue->getId()); ?>"><i
-                            class="icon-fixed-width icon-save"></i>
-                            <?php echo __('Edit'); ?></a>
-                        </li>
-<?php }
-else {
-    if ($thisstaff->isAdmin()) { ?>
-                        <li>
-                            <a class="no-pjax"
-                            href="queues.php?id=<?php echo $queue->id; ?>"><i
                             class="icon-fixed-width icon-pencil"></i>
                             <?php echo __('Edit'); ?></a>
                         </li>
-<?php }
-# Anyone has permission to create personal sub-queues
-?>
                         <li>
                             <a class="no-pjax" href="#"
-                              data-dialog="ajax.php/tickets/search?parent_id=<?php
-                              echo $queue->id; ?>"><i
+                              data-dialog="ajax.php/tickets/search/create?pid=<?php
+                              echo $queue->getId(); ?>"><i
                             class="icon-fixed-width icon-plus-sign"></i>
-                            <?php echo __('Add Personal Queue'); ?></a>
-                        </li>
-<?php
-}
-if ($thisstaff->isAdmin()) { ?>
-                        <li>
-                            <a class="no-pjax"
-                            href="queues.php?a=sub&amp;id=<?php echo $queue->id; ?>"><i
-                            class="icon-fixed-width icon-level-down"></i>
                             <?php echo __('Add Sub Queue'); ?></a>
                         </li>
-                        <li>
-                            <a class="no-pjax"
-                            href="queues.php?a=clone&amp;id=<?php echo $queue->id; ?>"><i
-                            class="icon-fixed-width icon-copy"></i>
-                            <?php echo __('Clone'); ?></a>
-                        </li>
-<?php }
-if (
-    $queue->id > 0
-    && (
-        ($thisstaff->isAdmin() && $queue->parent_id)
-        || $queue->isPrivate()
-)) { ?>
+<?php
+
+if ($queue->id > 0 && $queue->isOwner($thisstaff)) { ?>
                         <li class="danger">
                             <a class="no-pjax confirm-action" href="#"
                                 data-dialog="ajax.php/queue/<?php
diff --git a/include/staff/templates/savedqueue-settings.tmpl.php b/include/staff/templates/savedqueue-settings.tmpl.php
new file mode 100644
index 0000000000000000000000000000000000000000..42d36d57bf1006021c67e219c57e357a83cf5568
--- /dev/null
+++ b/include/staff/templates/savedqueue-settings.tmpl.php
@@ -0,0 +1,63 @@
+<div style="overflow-y: auto; height:auto; max-height: 350px;">
+ <div>
+    <div class="faded"><strong><?php echo __('Name'); ?></strong></div>
+    <div>
+    <?php
+    if ($queue->checkOwnership($thisstaff)) { ?>
+    <input name="queue-name" type="text" size="40"
+        value="<?php echo Format::htmlchars($queue->getName()); ?>"
+        placeholder="<?php echo __('Search Title'); ?>">
+    <?php
+    } else {
+        echo Format::htmlchars($queue->getName());
+    } ?>
+    </div>
+    <div class="error" id="name-error"><?php echo
+    Format::htmlchars($errors['queue-name']); ?></div>
+ </div>
+ <div>
+    <div class="faded"><strong><?php echo __("Quick Filter"); ?></strong></div>
+    <div>
+        <select name="filter">
+          <option value="" <?php if ($queue->filter == "")
+              echo 'selected="selected"'; ?>>— <?php echo __('None'); ?> —</option>
+          <option value="::" <?php if ($queue->filter == "::")
+              echo 'selected="selected"'; ?>>— <?php echo __('Inherit from parent');
+            if ($queue->parent
+                && ($qf = $queue->parent->getQuickFilterField()))
+                echo sprintf(' (%s)', $qf->getLabel()); ?> —</option>
+<?php foreach ($queue->getSupportedFilters() as $path => $f) {
+        list($label, $field) = $f;
+?>
+          <option value="<?php echo $path; ?>"
+            <?php if ($path == $queue->filter) echo 'selected="selected"'; ?>
+            ><?php echo Format::htmlchars($label); ?></option>
+<?php } ?>
+         </select>
+      </div>
+        <div class="error"><?php
+            echo Format::htmlchars($errors['filter']); ?></div>
+ </div>
+ <div>
+    <div class="faded"><strong><?php echo __("Defaut Sorting"); ?></strong></div>
+    <div>
+        <select name="sort_id">
+         <option value="" <?php if ($queue->sort_id == 0)
+            echo 'selected="selected"'; ?>>— <?php echo __('None'); ?> —</option>
+          <option value="::" <?php if ($queue->isDefaultSortInherited() &&
+                  $queue->parent)
+              echo 'selected="selected"'; ?>>— <?php echo __('Inherit from parent');
+            if ($queue->parent
+                && ($sort = $queue->parent->getDefaultSort()))
+                echo sprintf(' (%s)', $sort->getName()); ?> —</option>
+<?php foreach ($queue->getSortOptions() as $sort) { ?>
+          <option value="<?php echo $sort->id; ?>"
+            <?php if ($sort->id == $queue->sort_id) echo 'selected="selected"'; ?>
+            ><?php echo Format::htmlchars($sort->getName()); ?></option>
+<?php } ?>
+        </select>
+      </div>
+        <div class="error"><?php
+            echo Format::htmlchars($errors['sort_id']); ?></div>
+  </div>
+</div>
diff --git a/include/upgrader/streams/core.sig b/include/upgrader/streams/core.sig
index 4ad11e1f415bd953c9e8a80441aa12cdb7bbf5dc..5c4c675cad5ffbfde918a49029645fc955d772dd 100644
--- a/include/upgrader/streams/core.sig
+++ b/include/upgrader/streams/core.sig
@@ -1 +1 @@
-e7dfe82131b906a14f6a13163943855f
+70921d5c3920ab240b08bdd55bc894c8
diff --git a/include/upgrader/streams/core/e7dfe821-70921d5c.patch.sql b/include/upgrader/streams/core/e7dfe821-70921d5c.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..3547e6698f15cb0adcff927510968cb168bb1f08
--- /dev/null
+++ b/include/upgrader/streams/core/e7dfe821-70921d5c.patch.sql
@@ -0,0 +1,43 @@
+/**
+* @signature 70921d5c3920ab240b08bdd55bc894c8
+* @version v1.11.0
+* @title Make Public CustomQueues Configurable
+*
+* This patch adds staff_id to queue_columns table and queue_config table to
+* allow for ability to customize public queue columns as well as additional
+* settings
+*
+*/
+
+-- Add staff_id to queue_columns table
+ALTER TABLE `%TABLE_PREFIX%queue_columns`
+    ADD `staff_id` int(11) unsigned NOT NULL AFTER  `column_id`;
+
+-- Set staff_id to 0 for default columns
+UPDATE `%TABLE_PREFIX%queue_columns`
+    SET `staff_id` = 0;
+
+-- Add staff_id to PRIMARY KEY
+ALTER TABLE `%TABLE_PREFIX%queue_columns`
+    DROP PRIMARY KEY,
+    ADD PRIMARY KEY (`queue_id`, `column_id`, `staff_id`);
+
+-- Set staff_id to 0 for public queues
+UPDATE `%TABLE_PREFIX%queue`
+    SET `staff_id` = 0
+    WHERE (`flags` & 1) >0;
+
+-- Add bridge table for public Queues staff configuration & settings
+DROP TABLE IF EXISTS `%TABLE_PREFIX%queue_config`;
+CREATE TABLE `%TABLE_PREFIX%queue_config` (
+  `queue_id` int(11) unsigned NOT NULL,
+  `staff_id` int(11) unsigned NOT NULL,
+  `setting` text,
+  `updated` datetime NOT NULL,
+  PRIMARY KEY (`queue_id`,`staff_id`)
+) DEFAULT CHARSET=utf8;
+
+ -- Finished with patch
+UPDATE `%TABLE_PREFIX%config`
+    SET `value` = '70921d5c3920ab240b08bdd55bc894c8'
+    WHERE `key` = 'schema_signature' AND `namespace` = 'core';
diff --git a/scp/ajax.php b/scp/ajax.php
index 039af6b3e48d838eeabd2506dffbfc67c3055ed7..c746da68d0650c46ce0b524f789803e70d6b1582 100644
--- a/scp/ajax.php
+++ b/scp/ajax.php
@@ -177,6 +177,7 @@ $dispatcher = patterns('',
             url_post('^$', 'doSearch'),
             url_get('^/(?P<id>\d+)$', 'editSearch'),
             url_get('^/adhoc,(?P<key>[\w=/+]+)$', 'getAdvancedSearchDialog'),
+            url_get('^/create$', 'createSearch'),
             url_post('^/(?P<id>\d+)/save$', 'saveSearch'),
             url_post('^/save$', 'saveSearch'),
             url_delete('^/(?P<id>\d+)$', 'deleteSearch'),
diff --git a/scp/js/scp.js b/scp/js/scp.js
index fb2a6428a9c8e1884186968236b252f9a197eda7..b40837fc01b7cfc53eddfb940d1ae2ef38cf5b02 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -711,7 +711,9 @@ $.dialog = function (url, codes, cb, options) {
                         }
                         catch (e) { }
                         $('div.body', $popup).html(resp);
-                        $popup.effect('shake');
+                        if ($('#msg_error, .error-banner', $popup).length) {
+                            $popup.effect('shake');
+                        }
                         $('#msg_notice, #msg_error', $popup).delay(5000).slideUp();
                         $('div.tab_content[id] div.error:not(:empty)', $popup).each(function() {
                           var div = $(this).closest('.tab_content');
diff --git a/scp/queues.php b/scp/queues.php
index c2a641614e47116bcd2cd9efb0ebc38b331d20eb..ba5f33b78baf9bdaec51b1da074993030703030c 100644
--- a/scp/queues.php
+++ b/scp/queues.php
@@ -20,7 +20,7 @@ require('admin.inc.php');
 $nav->setTabActive('settings', 'settings.php?t='.urlencode($_GET['t']));
 $errors = array();
 
-if ($_REQUEST['id']) {
+if ($_REQUEST['id'] && is_numeric($_REQUEST['id'])) {
     $queue = CustomQueue::lookup($_REQUEST['id']);
 }
 
@@ -43,11 +43,14 @@ if ($_POST) {
     case 'create':
         $queue = CustomQueue::create(array(
             'flags' => CustomQueue::FLAG_PUBLIC,
-            'root' => $_POST['root'] ?: 'Ticket'
+            'staff_id' => 0,
+            'title' => $_POST['queue-name'],
+            'root' => $_POST['root'] ?: 'T'
         ));
 
         if ($queue->update($_POST, $errors) && $queue->save(true)) {
-            $msg = sprintf(__('Successfully added %s'), Format::htmlchars($_POST['name']));
+            $msg = sprintf(__('Successfully added %s'),
+                    Format::htmlchars($queue->getName()));
         }
         elseif (!$errors['err']) {
             $errors['err']=sprintf(__('Unable to add %s. Correct error(s) below and try again.'),
diff --git a/scp/tickets.php b/scp/tickets.php
index 773744a69f47513a5febf1451c4820ce9f3826dd..2d04b89efc48ccedab6099f58bee837d72ac2b9d 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -110,10 +110,10 @@ if (!$ticket) {
     $_SESSION[$queue_key] = $queue_id;
 
     if ((int) $queue_id && !$queue) {
-        $queue = CustomQueue::lookup($queue_id);
+        $queue = SavedQueue::lookup($queue_id);
     }
     if (!$queue) {
-        $queue = CustomQueue::lookup($cfg->getDefaultTicketQueueId());
+        $queue = SavedQueue::lookup($cfg->getDefaultTicketQueueId());
     }
 
     // Set the queue_id for navigation to turn a top-level item bold
@@ -456,7 +456,7 @@ $nav->setTabActive('tickets');
 $nav->addSubNavInfo('jb-overflowmenu', 'customQ_nav');
 
 // Fetch ticket queues organized by root and sub-queues
-$queues = CustomQueue::queues()
+$queues = SavedQueue::queues()
     ->filter(Q::any(array(
         'flags__hasbit' => CustomQueue::FLAG_PUBLIC,
         'staff_id' => $thisstaff->getId(),
diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql
index 45482f83f8a448904a1e054406cd9a25c83c9c61..5c1ddc7ea1a46c736dd7d05f2037925a1f75131f 100644
--- a/setup/inc/streams/core/install-mysql.sql
+++ b/setup/inc/streams/core/install-mysql.sql
@@ -876,11 +876,12 @@ DROP TABLE IF EXISTS `%TABLE_PREFIX%queue_columns`;
 CREATE TABLE `%TABLE_PREFIX%queue_columns` (
   `queue_id` int(11) unsigned NOT NULL,
   `column_id` int(11) unsigned NOT NULL,
+  `staff_id` int(11) unsigned NOT NULL,
   `bits` int(10) unsigned NOT NULL DEFAULT '0',
   `sort` int(10) unsigned NOT NULL DEFAULT '1',
   `heading` varchar(64) DEFAULT NULL,
   `width` int(10) unsigned NOT NULL DEFAULT '100',
-  PRIMARY KEY (`queue_id`, `column_id`)
+  PRIMARY KEY (`queue_id`, `column_id`, `staff_id`)
 ) DEFAULT CHARSET=utf8;
 
 DROP TABLE IF EXISTS `%TABLE_PREFIX%queue_sort`;
@@ -913,6 +914,15 @@ CREATE TABLE `%TABLE_PREFIX%queue_export` (
   KEY `queue_id` (`queue_id`)
 ) DEFAULT CHARSET=utf8;
 
+DROP TABLE IF EXISTS `%TABLE_PREFIX%queue_config`;
+CREATE TABLE `%TABLE_PREFIX%queue_config` (
+  `queue_id` int(11) unsigned NOT NULL,
+  `staff_id` int(11) unsigned NOT NULL,
+  `setting` text,
+  `updated` datetime NOT NULL,
+  PRIMARY KEY (`queue_id`,`staff_id`)
+) DEFAULT CHARSET=utf8;
+
 DROP TABLE IF EXISTS `%TABLE_PREFIX%translation`;
 CREATE TABLE `%TABLE_PREFIX%translation` (
   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,