diff --git a/include/class.staff.php b/include/class.staff.php
index 33f9cef7f14a870da5d7b5e37a34393c8bbd8a4f..231717bef71bf8aa720b5f67c7f22a19fadc1f5b 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -22,6 +22,18 @@ include_once(INCLUDE_DIR.'class.passwd.php');
 include_once(INCLUDE_DIR.'class.user.php');
 include_once(INCLUDE_DIR.'class.auth.php');
 
+class StaffModel extends VerySimpleModel {
+    static $meta = array(
+        'table' => STAFF_TABLE,
+        'pk' => array('staff_id'),
+        'joins' => array(
+            'dept' => array(
+                'constraint' => array('dept_id' => 'Dept.dept_id'),
+            ),
+        ),
+    );
+}
+
 class Staff extends AuthenticatedUser {
 
     var $ht;
diff --git a/include/class.ticket.php b/include/class.ticket.php
index e21b1bc46cacb269fb9b5befe0cee12e82e065d1..81201705984c97f9c26b0a00cfa30d1f46762045 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -34,6 +34,82 @@ require_once(INCLUDE_DIR.'class.user.php');
 require_once(INCLUDE_DIR.'class.collaborator.php');
 require_once(INCLUDE_DIR.'class.faq.php');
 
+class TicketModel extends VerySimpleModel {
+    static $meta = array(
+        'table' => TICKET_TABLE,
+        'pk' => array('ticket_id'),
+        'joins' => array(
+            'user' => array(
+                'constraint' => array('user_id' => 'User.id')
+            ),
+            'status' => array(
+                'constraint' => array('status_id' => 'TicketStatus.id')
+            ),
+            'lock' => array(
+                'reverse' => 'TicketLock.ticket',
+                'list' => false,
+                'null' => true,
+            ),
+            'dept' => array(
+                'constraint' => array('dept_id' => 'Dept.dept_id'),
+            ),
+            'staff' => array(
+                'constraint' => array('staff_id' => 'StaffModel.staff_id'),
+                'null' => true,
+            ),
+            'team' => array(
+                'constraint' => array('team_id' => 'Team.team_id'),
+                'null' => true,
+            ),
+            'topic' => array(
+                'constraint' => array('topic_id' => 'Topic.topic_id'),
+                'null' => true,
+            ),
+            'cdata' => array(
+                'reverse' => 'TicketCData.ticket',
+                'list' => false,
+            ),
+        )
+    );
+
+    function getId() {
+        return $this->ticket_id;
+    }
+
+    function getEffectiveDate() {
+         return max(
+             strtotime($this->lastmessage),
+             strtotime($this->closed),
+             strtotime($this->reopened),
+             strtotime($this->created)
+         );
+    }
+
+    function delete() {
+
+        if (($ticket=Ticket::lookup($this->getId())) && @$ticket->delete())
+            return true;
+
+        return false;
+    }
+}
+
+class TicketCData extends VerySimpleModel {
+    static $meta = array(
+        'pk' => array('ticket_id'),
+        'joins' => array(
+            'ticket' => array(
+                'constraint' => array('ticket_id' => 'TicketModel.ticket_id'),
+            ),
+            ':priority' => array(
+                'constraint' => array('priority' => 'Priority.priority_id'),
+                'null' => true,
+            ),
+        ),
+    );
+}
+TicketCData::$meta['table'] = TABLE_PREFIX . 'ticket__cdata';
+
 
 class Ticket {
 
diff --git a/include/class.user.php b/include/class.user.php
index 5c927b3f15d534e6f37472287ba0d899b9864829..13521ad42cf1ff2b95238767f833face6a1357cc 100644
--- a/include/class.user.php
+++ b/include/class.user.php
@@ -33,33 +33,6 @@ class UserEmailModel extends VerySimpleModel {
     }
 }
 
-class TicketModel extends VerySimpleModel {
-    static $meta = array(
-        'table' => TICKET_TABLE,
-        'pk' => array('ticket_id'),
-        'joins' => array(
-            'user' => array(
-                'constraint' => array('user_id' => 'UserModel.id')
-            ),
-            'status' => array(
-                'constraint' => array('status_id' => 'TicketStatus.id')
-            )
-        )
-    );
-
-    function getId() {
-        return $this->ticket_id;
-    }
-
-    function delete() {
-
-        if (($ticket=Ticket::lookup($this->getId())) && @$ticket->delete())
-            return true;
-
-        return false;
-    }
-}
-
 class UserModel extends VerySimpleModel {
     static $meta = array(
         'table' => USER_TABLE,
@@ -1163,8 +1136,4 @@ class UserList extends ListObject {
         return $list ? implode(', ', $list) : '';
     }
 }
-
-require_once(INCLUDE_DIR . 'class.organization.php');
-User::_inspect();
-UserAccount::_inspect();
 ?>
diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php
index f27de7cf3f5a79c9b902f0ecc72a97615651bba7..b0dca99dd0d197f0a1d7fb235f381e8936eabe0d 100644
--- a/include/staff/tickets.inc.php
+++ b/include/staff/tickets.inc.php
@@ -1,311 +1,91 @@
 <?php
-if(!defined('OSTSCPINC') || !$thisstaff || !@$thisstaff->isStaff()) die('Access Denied');
+$search = SavedSearch::create();
+$tickets = TicketModel::objects();
+$clear_button = false;
+// Add "other" fields (via $_POST['other'][])
 
-$qstr='&'; //Query string collector
-if($_REQUEST['status']) { //Query string status has nothing to do with the real status used below; gets overloaded.
-    $qstr.='status='.urlencode($_REQUEST['status']);
-}
-
-//See if this is a search
-$search=($_REQUEST['a']=='search');
-$searchTerm='';
-//make sure the search query is 3 chars min...defaults to no query with warning message
-if($search) {
-  $searchTerm=$_REQUEST['query'];
-  if( ($_REQUEST['query'] && strlen($_REQUEST['query'])<3)
-      || (!$_REQUEST['query'] && isset($_REQUEST['basic_search'])) ){ //Why do I care about this crap...
-      $search=false; //Instead of an error page...default back to regular query..with no search.
-      $errors['err']=__('Search term must be more than 3 chars');
-      $searchTerm='';
-  }
-}
-$showoverdue=$showanswered=false;
-$staffId=0; //Nothing for now...TODO: Allow admin and manager to limit tickets to single staff level.
-$showassigned= true; //show Assigned To column - defaults to true
-
-//Get status we are actually going to use on the query...making sure it is clean!
-$status=null;
 switch(strtolower($_REQUEST['status'])){ //Status is overloaded
-    case 'open':
-        $status='open';
-		$results_type=__('Open Tickets');
-        break;
-    case 'closed':
-        $status='closed';
-		$results_type=__('Closed Tickets');
-        $showassigned=true; //closed by.
-        break;
-    case 'overdue':
-        $status='open';
-        $showoverdue=true;
-        $results_type=__('Overdue Tickets');
-        break;
-    case 'assigned':
-        $status='open';
-        $staffId=$thisstaff->getId();
-        $results_type=__('My Tickets');
-        break;
-    case 'answered':
-        $status='open';
-        $showanswered=true;
-        $results_type=__('Answered Tickets');
+case 'closed':
+    $status='closed';
+    $results_type=__('Closed Tickets');
+    $showassigned=true; //closed by.
+    break;
+case 'overdue':
+    $status='open';
+    $results_type=__('Overdue Tickets');
+    $tickets->filter(array('isoverdue'=>1));
+    break;
+case 'assigned':
+    $status='open';
+    $staffId=$thisstaff->getId();
+    $results_type=__('My Tickets');
+    $tickets->filter(array('staff_id'=>$thisstaff->getId()));
+    break;
+case 'answered':
+    $status='open';
+    $showanswered=true;
+    $results_type=__('Answered Tickets');
+    $tickets->filter(array('isanswered'=>1));
+    break;
+default:
+    if (isset($_GET['clear_filter']))
+        unset($_SESSION['advsearch']);
+    if (isset($_SESSION['advsearch'])) {
+        $form = $search->getForm();
+            $form->loadState($_SESSION['advsearch']);
+        $tickets = $search->mangleQuerySet($tickets, $form);
+        $results_type=__('Advanced Search')
+            . '<a class="action-button" href="?clear_filter"><i class="icon-ban-circle"></i> <em>' . __('clear') . '</em></a>';
         break;
-    default:
-        if (!$search && !isset($_REQUEST['advsid'])) {
-            $_REQUEST['status']=$status='open';
-            $results_type=__('Open Tickets');
-        }
-}
-
-$qwhere ='';
-/*
-   STRICT DEPARTMENTS BASED PERMISSION!
-   User can also see tickets assigned to them regardless of the ticket's dept.
-*/
-
-$depts=$thisstaff->getDepts();
-$qwhere =' WHERE ( '
-        .'  ( ticket.staff_id='.db_input($thisstaff->getId())
-        .' AND status.state="open") ';
-
-if(!$thisstaff->showAssignedOnly())
-    $qwhere.=' OR ticket.dept_id IN ('.($depts?implode(',', db_input($depts)):0).')';
-
-if(($teams=$thisstaff->getTeams()) && count(array_filter($teams)))
-    $qwhere.=' OR (ticket.team_id IN ('.implode(',', db_input(array_filter($teams)))
-            .') AND status.state="open") ';
-
-$qwhere .= ' )';
-
-//STATUS to states
-$states = array(
-    'open' => array('open'),
-    'closed' => array('closed'));
-
-if($status && isset($states[$status])) {
-    $qwhere.=' AND status.state IN (
-                '.implode(',', db_input($states[$status])).' ) ';
-}
-
-if (isset($_REQUEST['uid']) && $_REQUEST['uid']) {
-    $qwhere .= ' AND (ticket.user_id='.db_input($_REQUEST['uid'])
-            .' OR collab.user_id='.db_input($_REQUEST['uid']).') ';
-    $qstr .= '&uid='.urlencode($_REQUEST['uid']);
-}
-
-//Queues: Overloaded sub-statuses  - you've got to just have faith!
-if($staffId && ($staffId==$thisstaff->getId())) { //My tickets
-    $results_type=__('Assigned Tickets');
-    $qwhere.=' AND ticket.staff_id='.db_input($staffId);
-    $showassigned=false; //My tickets...already assigned to the staff.
-}elseif($showoverdue) { //overdue
-    $qwhere.=' AND ticket.isoverdue=1 ';
-}elseif($showanswered) { ////Answered
-    $qwhere.=' AND ticket.isanswered=1 ';
-}elseif(!strcasecmp($status, 'open') && !$search) { //Open queue (on search OPEN means all open tickets - regardless of state).
-    //Showing answered tickets on open queue??
-    if(!$cfg->showAnsweredTickets())
-        $qwhere.=' AND ticket.isanswered=0 ';
-
-    /* Showing assigned tickets on open queue?
-       Don't confuse it with show assigned To column -> F'it it's confusing - just trust me!
-     */
-    if(!($cfg->showAssignedTickets() || $thisstaff->showAssignedTickets())) {
-        $qwhere.=' AND ticket.staff_id=0 '; //XXX: NOT factoring in team assignments - only staff assignments.
-        $showassigned=false; //Not showing Assigned To column since assigned tickets are not part of open queue
     }
+    // Fall-through and show open tickets
+case 'open':
+    $status='open';
+    $results_type=__('Open Tickets');
+    $tickets->filter(array('isanswered'=>0));
+    break;
 }
 
-//Search?? Somebody...get me some coffee
-$deep_search=false;
-$order_by=$order=null;
-if($search):
-    $qstr.='&a='.urlencode($_REQUEST['a']);
-    $qstr.='&t='.urlencode($_REQUEST['t']);
-
-    //query
-    if($searchTerm){
-        $qstr.='&query='.urlencode($searchTerm);
-        $queryterm=db_real_escape($searchTerm,false); //escape the term ONLY...no quotes.
-        if (is_numeric($searchTerm)) {
-            $qwhere.=" AND ticket.`number` LIKE '$queryterm%'";
-        } elseif (strpos($searchTerm,'@') && Validator::is_email($searchTerm)) {
-            //pulling all tricks!
-            # XXX: What about searching for email addresses in the body of
-            #      the thread message
-            $qwhere.=" AND email.address='$queryterm'";
-        } else {//Deep search!
-            //This sucks..mass scan! search anything that moves!
-            require_once(INCLUDE_DIR.'ajax.tickets.php');
-
-            $tickets = TicketsAjaxApi::_search(array('query'=>$queryterm));
-            if (count($tickets)) {
-                $ticket_ids = implode(',',db_input($tickets));
-                $qwhere .= ' AND ticket.ticket_id IN ('.$ticket_ids.')';
-                $order_by = 'FIELD(ticket.ticket_id, '.$ticket_ids.')';
-                $order = ' ';
-            }
-            else
-                // No hits -- there should be an empty list of results
-                $qwhere .= ' AND false';
-        }
-   }
-
-endif;
-
-if ($_REQUEST['advsid'] && isset($_SESSION['adv_'.$_REQUEST['advsid']])) {
-    $ticket_ids = implode(',', db_input($_SESSION['adv_'.$_REQUEST['advsid']]));
-    $qstr.='advsid='.$_REQUEST['advsid'];
-    $qwhere .= ' AND ticket.ticket_id IN ('.$ticket_ids.')';
-    // Thanks, http://stackoverflow.com/a/1631794
-    $order_by = 'FIELD(ticket.ticket_id, '.$ticket_ids.')';
-    $order = ' ';
-}
-
-$sortOptions=array('date'=>'effective_date','ID'=>'ticket.`number`*1',
-    'pri'=>'pri.priority_urgency','name'=>'user.name','subj'=>'cdata.subject',
-    'status'=>'status.name','assignee'=>'assigned','staff'=>'staff',
-    'dept'=>'dept.dept_name');
-
-$orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
-
-//Sorting options...
-$queue = isset($_REQUEST['status'])?strtolower($_REQUEST['status']):$status;
-if($_REQUEST['sort'] && $sortOptions[$_REQUEST['sort']])
-    $order_by =$sortOptions[$_REQUEST['sort']];
-elseif($sortOptions[$_SESSION[$queue.'_tickets']['sort']]) {
-    $_REQUEST['sort'] = $_SESSION[$queue.'_tickets']['sort'];
-    $_REQUEST['order'] = $_SESSION[$queue.'_tickets']['order'];
-
-    $order_by = $sortOptions[$_SESSION[$queue.'_tickets']['sort']];
-    $order = $_SESSION[$queue.'_tickets']['order'];
-}
-
-if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])])
-    $order=$orderWays[strtoupper($_REQUEST['order'])];
-
-//Save sort order for sticky sorting.
-if($_REQUEST['sort'] && $queue) {
-    $_SESSION[$queue.'_tickets']['sort'] = $_REQUEST['sort'];
-    $_SESSION[$queue.'_tickets']['order'] = $_REQUEST['order'];
-}
-
-//Set default sort by columns.
-if(!$order_by ) {
-    if($showanswered)
-        $order_by='ticket.lastresponse, ticket.created'; //No priority sorting for answered tickets.
-    elseif(!strcasecmp($status,'closed'))
-        $order_by='ticket.closed, ticket.created'; //No priority sorting for closed tickets.
-    elseif($showoverdue) //priority> duedate > age in ASC order.
-        $order_by='pri.priority_urgency ASC, ISNULL(ticket.duedate) ASC, ticket.duedate ASC, effective_date ASC, ticket.created';
-    else //XXX: Add due date here?? No -
-        $order_by='pri.priority_urgency ASC, effective_date DESC, ticket.created';
-}
-
-$order=$order?$order:'DESC';
-if($order_by && strpos($order_by,',') && $order)
-    $order_by=preg_replace('/(?<!ASC|DESC),/', " $order,", $order_by);
-
-$sort=$_REQUEST['sort']?strtolower($_REQUEST['sort']):'pri.priority_urgency'; //Urgency is not on display table.
-$x=$sort.'_sort';
-$$x=' class="'.strtolower($order).'" ';
-
-if($_GET['limit'])
-    $qstr.='&limit='.urlencode($_GET['limit']);
-
-$qselect ='SELECT ticket.ticket_id,tlock.lock_id,ticket.`number`,ticket.dept_id,ticket.staff_id,ticket.team_id '
-    .' ,user.name'
-    .' ,email.address as email, dept.dept_name, status.state '
-         .' ,status.name as status,ticket.source,ticket.isoverdue,ticket.isanswered,ticket.created ';
-
-$qfrom=' FROM '.TICKET_TABLE.' ticket '.
-       ' LEFT JOIN '.TICKET_STATUS_TABLE. ' status
-            ON (status.id = ticket.status_id) '.
-       ' LEFT JOIN '.USER_TABLE.' user ON user.id = ticket.user_id'.
-       ' LEFT JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id'.
-       ' LEFT JOIN '.DEPT_TABLE.' dept ON ticket.dept_id=dept.dept_id ';
-
-if ($_REQUEST['uid'])
-    $qfrom.=' LEFT JOIN '.TICKET_COLLABORATOR_TABLE.' collab
-        ON (ticket.ticket_id = collab.ticket_id )';
-
-
-$sjoin='';
-
-if($search && $deep_search) {
-    $sjoin.=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON (ticket.ticket_id=thread.ticket_id )';
-}
-
-//get ticket count based on the query so far..
-$total=db_count("SELECT count(DISTINCT ticket.ticket_id) $qfrom $sjoin $qwhere");
-//pagenate
+// Apply primary ticket status
+if ($status)
+    $tickets->filter(array('status__state'=>$status));
+
+// Impose visibility constraints
+// ------------------------------------------------------------
+// -- Open and assigned to me
+$visibility = array(
+    new Q(array('status__state'=>'open', 'staff_id' => $thisstaff->getId()))
+);
+// -- Routed to a department of mine
+if (!$thisstaff->showAssignedOnly() && ($depts=$thisstaff->getDepts()))
+    $visibility[] = new Q(array('dept_id__in' => $depts));
+// -- Open and assigned to a team of mine
+if (($teams = $thisstaff->getTeams()) && count(array_filter($teams)))
+    $visibility[] = new Q(array(
+        'team_id__in' => array_filter($teams), 'status__state'=>'open'
+    ));
+$tickets->filter(Q::any($visibility));
+
+// Select pertinent columns
+// ------------------------------------------------------------
+$tickets->select_related('lock', 'dept', 'staff', 'user', 'user__default_email', 'topic', 'status', 'cdata', 'cdata__:priority');
+
+// Apply requested quick filter
+
+// Apply requested sorting
+
+// Apply requested pagination
 $pagelimit=($_GET['limit'] && is_numeric($_GET['limit']))?$_GET['limit']:PAGE_LIMIT;
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
-$pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
-
-//ADD attachment,priorities, lock and other crap
-$qselect.=' ,IF(ticket.duedate IS NULL,IF(sla.id IS NULL, NULL, DATE_ADD(ticket.created, INTERVAL sla.grace_period HOUR)), ticket.duedate) as duedate '
-         .' ,CAST(GREATEST(IFNULL(ticket.lastmessage, 0), IFNULL(ticket.closed, 0), IFNULL(ticket.reopened, 0), ticket.created) as datetime) as effective_date '
-         .' ,ticket.created as ticket_created, CONCAT_WS(" ", staff.firstname, staff.lastname) as staff, team.name as team '
-         .' ,IF(staff.staff_id IS NULL,team.name,CONCAT_WS(" ", staff.lastname, staff.firstname)) as assigned '
-         .' ,IF(ptopic.topic_pid IS NULL, topic.topic, CONCAT_WS(" / ", ptopic.topic, topic.topic)) as helptopic '
-         .' ,cdata.priority as priority_id, cdata.subject, pri.priority_desc, pri.priority_color';
-
-$qfrom.=' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()
-               AND tlock.staff_id!='.db_input($thisstaff->getId()).') '
-       .' LEFT JOIN '.STAFF_TABLE.' staff ON (ticket.staff_id=staff.staff_id) '
-       .' LEFT JOIN '.TEAM_TABLE.' team ON (ticket.team_id=team.team_id) '
-       .' LEFT JOIN '.SLA_TABLE.' sla ON (ticket.sla_id=sla.id AND sla.isactive=1) '
-       .' LEFT JOIN '.TOPIC_TABLE.' topic ON (ticket.topic_id=topic.topic_id) '
-       .' LEFT JOIN '.TOPIC_TABLE.' ptopic ON (ptopic.topic_id=topic.topic_pid) '
-       .' LEFT JOIN '.TABLE_PREFIX.'ticket__cdata cdata ON (cdata.ticket_id = ticket.ticket_id) '
-       .' LEFT JOIN '.PRIORITY_TABLE.' pri ON (pri.priority_id = cdata.priority)';
+$pageNav=new Pagenate($tickets->count(), $page,$pagelimit);
 
 TicketForm::ensureDynamicDataView();
 
-$query="$qselect $qfrom $qwhere ORDER BY $order_by $order LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
-//echo $query;
-$hash = md5($query);
-$_SESSION['search_'.$hash] = $query;
-$res = db_query($query);
-$showing=db_num_rows($res)? ' &mdash; '.$pageNav->showing():"";
-if(!$results_type)
-    $results_type = sprintf(__('%s Tickets' /* %s will be a status such as 'open' */),
-        mb_convert_case($status, MB_CASE_TITLE));
-
-if($search)
-    $results_type.= ' ('.__('Search Results').')';
-
-$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting..
-
-// Fetch the results
-$results = array();
-while ($row = db_fetch_array($res)) {
-    $results[$row['ticket_id']] = $row;
-}
+// Save the query to the session for exporting
+$_SESSION[':Q:tickets'] = $tickets;
 
-// Fetch attachment and thread entry counts
-if ($results) {
-    $counts_sql = 'SELECT ticket.ticket_id,
-        count(DISTINCT attach.attach_id) as attachments,
-        count(DISTINCT thread.id) as thread_count,
-        count(DISTINCT collab.id) as collaborators
-        FROM '.TICKET_TABLE.' ticket
-        LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (ticket.ticket_id=attach.ticket_id) '
-     .' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON ( ticket.ticket_id=thread.ticket_id) '
-     .' LEFT JOIN '.TICKET_COLLABORATOR_TABLE.' collab
-            ON ( ticket.ticket_id=collab.ticket_id) '
-     .' WHERE ticket.ticket_id IN ('.implode(',', db_input(array_keys($results))).')
-        GROUP BY ticket.ticket_id';
-    $ids_res = db_query($counts_sql);
-    while ($row = db_fetch_array($ids_res)) {
-        $results[$row['ticket_id']] += $row;
-    }
-}
-
-//YOU BREAK IT YOU FIX IT.
 ?>
+
 <!-- SEARCH FORM START -->
 <div id='basic_search'>
     <form action="tickets.php" method="get">
@@ -317,7 +97,7 @@ if ($results) {
                 autocomplete="off" autocorrect="off" autocapitalize="off"></td>
             <td><input type="submit" name="basic_search" class="button" value="<?php echo __('Search'); ?>"></td>
             <td>&nbsp;&nbsp;<a href="#" onclick="javascript:
-                $.dialog('ajax.php/tickets/advanced-search', 201);"
+                $.dialog('ajax.php/tickets/search', 201);"
                 >[<?php echo __('advanced'); ?>]</a>&nbsp;<i class="help-tip icon-question-sign" href="#advanced"></i></td>
         </tr>
     </table>
@@ -412,55 +192,54 @@ if ($results) {
         $subject_field = TicketForm::objects()->one()->getField('subject');
         $class = "row1";
         $total=0;
-        if($res && ($num=count($results))):
-            $ids=($errors && $_POST['tids'] && is_array($_POST['tids']))?$_POST['tids']:null;
-            foreach ($results as $row) {
-                $tag=$row['staff_id']?'assigned':'openticket';
+        $ids=($errors && $_POST['tids'] && is_array($_POST['tids']))?$_POST['tids']:null;
+        $subject_field = TicketForm::objects()->one()->getField('subject');
+        foreach ($tickets as $T) {
+            $total += 1;
+                $tag=$T->staff_id?'assigned':'openticket';
                 $flag=null;
-                if($row['lock_id'])
+                if($T->lock)
                     $flag='locked';
-                elseif($row['isoverdue'])
+                elseif($T->isoverdue)
                     $flag='overdue';
 
                 $lc='';
+                $dept = ($T->dept) ? $T->dept->getLocalName() : '';
                 if($showassigned) {
-                    if($row['staff_id'])
-                        $lc=sprintf('<span class="Icon staffAssigned">%s</span>',Format::truncate($row['staff'],40));
+                    if($T->staff_id)
+                        $lc=sprintf('<span class="Icon staffAssigned">%s</span>',Format::truncate($T->staff->getName(),40));
                     elseif($row['team_id'])
-                        $lc=sprintf('<span class="Icon teamAssigned">%s</span>',Format::truncate($row['team'],40));
+                        $lc=sprintf('<span class="Icon teamAssigned">%s</span>',Format::truncate($T->team->getName(),40));
                     else
                         $lc=' ';
                 }else{
-                    $lc=Format::truncate($row['dept_name'],40);
+                    $lc=Format::truncate($dept,40);
                 }
-                $tid=$row['number'];
-
-                $subject = Format::truncate($subject_field->display(
-                    $subject_field->to_php($row['subject']) ?: $row['subject']
-                ), 40);
+                $tid=$T->number;
+                $subject = Format::truncate($subject_field->display($subject_field->to_php($T->cdata->subject)),40);
                 $threadcount=$row['thread_count'];
-                if(!strcasecmp($row['state'],'open') && !$row['isanswered'] && !$row['lock_id']) {
+                if(!strcasecmp($T->status->state,'open') && !$T->isanswered && !$T->lock) {
                     $tid=sprintf('<b>%s</b>',$tid);
                 }
                 ?>
-            <tr id="<?php echo $row['ticket_id']; ?>">
+            <tr id="<?php echo $T->ticket_id; ?>">
                 <?php if($thisstaff->canManageTickets()) {
 
                     $sel=false;
-                    if($ids && in_array($row['ticket_id'], $ids))
+                    if($ids && in_array($T->ticket_id, $ids))
                         $sel=true;
                     ?>
                 <td align="center" class="nohover">
                     <input class="ckb" type="checkbox" name="tids[]"
-                        value="<?php echo $row['ticket_id']; ?>" <?php echo $sel?'checked="checked"':''; ?>>
+                        value="<?php echo $T->ticket_id; ?>" <?php echo $sel?'checked="checked"':''; ?>>
                 </td>
                 <?php } ?>
-                <td title="<?php echo $row['email']; ?>" nowrap>
-                  <a class="Icon <?php echo strtolower($row['source']); ?>Ticket ticketPreview" title="Preview Ticket"
-                    href="tickets.php?id=<?php echo $row['ticket_id']; ?>"><?php echo $tid; ?></a></td>
-                <td align="center" nowrap><?php echo Format::datetime($row['effective_date']); ?></td>
+                <td title="<?php echo $T->user->getDefaultEmailAddress(); ?>" nowrap>
+                  <a class="Icon <?php echo strtolower($T->source); ?>Ticket ticketPreview" title="Preview Ticket"
+                    href="tickets.php?id=<?php echo $T->ticket_id; ?>"><?php echo $tid; ?></a></td>
+                <td align="center" nowrap><?php echo Format::datetime($T->getEffectiveDate()); ?></td>
                 <td><a <?php if ($flag) { ?> class="Icon <?php echo $flag; ?>Ticket" title="<?php echo ucfirst($flag); ?> Ticket" <?php } ?>
-                    href="tickets.php?id=<?php echo $row['ticket_id']; ?>"><?php echo $subject; ?></a>
+                    href="tickets.php?id=<?php echo $T->ticket_id; ?>"><?php echo $subject; ?></a>
                      <?php
                         if ($threadcount>1)
                             echo "<small>($threadcount)</small>&nbsp;".'<i
@@ -472,31 +251,31 @@ if ($results) {
                     ?>
                 </td>
                 <td nowrap>&nbsp;<?php echo Format::htmlchars(
-                        Format::truncate($row['name'], 22, strpos($row['name'], '@'))); ?>&nbsp;</td>
+                        Format::truncate($T->user->getName(), 22, strpos($T->user->getName(), '@'))); ?>&nbsp;</td>
                 <?php
                 if($search && !$status){
-                    $displaystatus=ucfirst($row['status']);
-                    if(!strcasecmp($row['state'],'open'))
+                    $displaystatus=ucfirst($T->status);
+                    if(!strcasecmp($T->status->state,'open'))
                         $displaystatus="<b>$displaystatus</b>";
                     echo "<td>$displaystatus</td>";
                 } else { ?>
-                <td class="nohover" align="center" style="background-color:<?php echo $row['priority_color']; ?>;">
-                    <?php echo $row['priority_desc']; ?></td>
+                <td class="nohover" align="center" style="background-color:<?php echo $T->cdata->{':priority'}->priority_color; ?>;">
+                    <?php echo $T->cdata->{':priority'}->priority_desc; ?></td>
                 <?php
                 }
                 ?>
                 <td nowrap>&nbsp;<?php echo $lc; ?></td>
             </tr>
             <?php
-            } //end of while.
-        else: //not tickets found!! set fetch error.
+            } //end of foreach
+        if (!$total)
             $ferror=__('There are no tickets matching your criteria.');
-        endif; ?>
+        ?>
     </tbody>
     <tfoot>
      <tr>
         <td colspan="7">
-            <?php if($res && $num && $thisstaff->canManageTickets()){ ?>
+            <?php if($total && $thisstaff->canManageTickets()){ ?>
             <?php echo __('Select');?>:&nbsp;
             <a id="selectAll" href="#ckb"><?php echo __('All');?></a>&nbsp;&nbsp;
             <a id="selectNone" href="#ckb"><?php echo __('None');?></a>&nbsp;&nbsp;
@@ -511,7 +290,7 @@ if ($results) {
     </tfoot>
     </table>
     <?php
-    if($num>0){ //if we actually had any tickets returned.
+    if($total>0){ //if we actually had any tickets returned.
         echo '<div>&nbsp;'.__('Page').':'.$pageNav->getPageLinks().'&nbsp;';
         echo '<a class="export-csv no-pjax" href="?a=export&h='
             .$hash.'&status='.$_REQUEST['status'] .'">'.__('Export').'</a>&nbsp;<i class="help-tip icon-question-sign" href="#export"></i></div>';
@@ -557,3 +336,4 @@ $(function() {
     });
 });
 </script>
+
diff --git a/scp/css/dropdown.css b/scp/css/dropdown.css
index 4fb664178aaa2ab61f663d6b9219ad00740bf64d..54c277ec96063ac30b7e33c0ec6824e7a0939db7 100644
--- a/scp/css/dropdown.css
+++ b/scp/css/dropdown.css
@@ -131,3 +131,21 @@
   color: #777;
   text-decoration: none;
 }
+.action-buttons {
+    display: inline-block;
+    vertical-align: middle;
+}
+.action-buttons .action-button + .action-button {
+    margin-left: 0;
+    padding-left: 0;
+    border-left: none;
+    border-top-left-radius: 0;
+    border-bottom-left-radius: 0;
+}
+.action-buttons .action-button:not(:last-of-type) {
+    margin-right: 0;
+    padding-right: 0;
+    border-right: none;
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+}
diff --git a/scp/tickets.php b/scp/tickets.php
index 33300cb44131eaa48136d958f1160478fa20bd28..74fa99bff5df98e7fcc711d74bd8f398e0564872 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -448,7 +448,6 @@ $ost->addExtraHeader('<script type="text/javascript" src="js/ticket.js"></script
 $ost->addExtraHeader('<meta name="tip-namespace" content="tickets.queue" />',
     "$('#content').data('tipNamespace', 'tickets.queue');");
 
-$inc = 'tickets.inc.php';
 if($ticket) {
     $ost->setPageTitle(sprintf(__('Ticket #%s'),$ticket->getNumber()));
     $nav->setActiveSubMenu(-1);