diff --git a/include/class.orm.php b/include/class.orm.php
index 1c3ba561798665864e700e79ad9b902b7efac243..45b300f64ee99bd3eeae9d50c556929f5d6e547b 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -1618,7 +1618,7 @@ extends CachedResultSet {
      */
     function findFirst($criteria) {
         $records = $this->findAll($criteria, 1);
-        return @$records[0];
+        return count($records) > 0 ? $records[0] : null;
     }
 
     /**
diff --git a/include/class.queue.php b/include/class.queue.php
index 5952d9933668504fa585f773b90566e99680589d..77077e13824d41957a369681e109fc5e3e1ea4f2 100644
--- a/include/class.queue.php
+++ b/include/class.queue.php
@@ -35,16 +35,6 @@ class CustomQueue extends SavedSearch {
         ));
     }
 
-    static function getAnnotations($root) {
-        // Ticket annotations
-        return array(
-            'TicketThreadCount',
-            'ThreadAttachmentCount',
-            'OverdueFlagDecoration',
-            'TicketSourceDecoration'
-        );
-    }
-
     function getColumns() {
         if (!count($this->columns)) {
             foreach (parent::getColumns() as $c)
@@ -276,6 +266,17 @@ abstract class QueueColumnAnnotation {
     function getClassName() {
         return @$this->config['c'] ?: get_class();
     }
+
+    static function getAnnotations($root) {
+        // Ticket annotations
+        static $annotations;
+        if (!isset($annotations[$root])) {
+            foreach (get_declared_classes() as $class)
+                if (is_subclass_of($class, get_called_class()))
+                    $annotations[$root][] = $class;
+        }
+        return $annotations[$root];
+    }
 }
 
 class TicketThreadCount
@@ -360,6 +361,29 @@ extends QueueColumnAnnotation {
     }
 }
 
+class LockDecoration
+extends QueueColumnAnnotation {
+    static $icon = "lock";
+    static $desc = /* @trans */ 'Locked';
+
+    function annotate($query) {
+        global $thisstaff;
+
+        return $query
+            ->annotate(array(
+                '_locked' => new SqlExpr(array(new Q(array(
+                    'lock__expire__gt' => SqlFunction::NOW(),
+                    Q::not(array('lock__staff_id' => $thisstaff->getId())),
+                ))))
+            ));
+    }
+
+    function getDecoration($row, $text) {
+        if ($row['_locked'])
+            return sprintf('<span class="Icon lockedTicket"></span>');
+    }
+}
+
 class DataSourceField
 extends ChoiceField {
     function getChoices() {
diff --git a/include/staff/templates/queue-column.tmpl.php b/include/staff/templates/queue-column.tmpl.php
index 38ac9d2e4d669a3c3df20806a07bcfce9a7ed131..9890c73c6b25d00390aefac6d968970df2450d91 100644
--- a/include/staff/templates/queue-column.tmpl.php
+++ b/include/staff/templates/queue-column.tmpl.php
@@ -59,7 +59,7 @@ $data_form = $column->getDataConfigForm($_POST);
       <i class="icon-plus-sign"></i>
       <select class="add-annotation">
         <option>— <?php echo __("Add a annotation"); ?> —</option>
-<?php foreach (CustomQueue::getAnnotations('Ticket') as $class) {
+<?php foreach (QueueColumnAnnotation::getAnnotations('Ticket') as $class) {
         echo sprintf('<option data-icon="%s" value="%s">%s</option>',
           $class::$icon, $class, $class::getDescription());
       } ?>