Index: trunk/grails-app/controllers/InventoryItemDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/InventoryItemDetailedController.groovy	(revision 484)
+++ trunk/grails-app/controllers/InventoryItemDetailedController.groovy	(revision 485)
@@ -1,4 +1,6 @@
 import org.codehaus.groovy.grails.plugins.springsecurity.Secured
 import org.codehaus.groovy.grails.commons.ConfigurationHolder
+import com.zeddware.grails.plugins.filterpane.FilterUtils
+import org.springframework.web.servlet.support.RequestContextUtils as RCU
 
 @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
@@ -9,4 +11,5 @@
     def inventoryCsvService
     def inventoryItemService
+    def inventoryItemSearchService
     def inventoryMovementService
 
@@ -114,4 +117,7 @@
     }
 
+    /**
+    * Search for Inventory items.
+    */
     @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
     def search = {
@@ -120,21 +126,55 @@
             params.max = session.inventoryItemSearchParamsMax
 
-        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        // Protect filterPane.
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  1000)
 
         def inventoryItemInstanceList = []
         def inventoryItemInstanceTotal
-        def filterParams = [:]
-
-        // Quick Search:
-        if(!params.filter) {
-            inventoryItemInstanceList = InventoryItem.list( params )
-            inventoryItemInstanceTotal = InventoryItem.count()
-            filterParams = params
-        }
-        else {
-        // filterPane:
+        def filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+        def isFilterApplied = FilterUtils.isFilterApplied(params)
+
+        // Restore search unless a new search is being requested.
+        if(!params.quickSearch && !filterParams) {
+            if(session.inventoryItemQuickSearch)
+                params.quickSearch = session.inventoryItemQuickSearch
+            else if(session.inventoryItemSearchFilterParams) {
+                session.inventoryItemSearchFilterParams.each() { params[it.key] = it.value }
+                params.filter = session.inventoryItemSearchFilter
+                isFilterApplied = FilterUtils.isFilterApplied(params)
+            }
+        }
+
+        // Remember sort if supplied, otherwise try to restore.
+        if(params.sort && params.order) {
+             session.inventoryItemSearchSort = params.sort
+             session.inventoryItemSearchOrder = params.order
+        }
+        else if(session.inventoryItemSearchSort && session.inventoryItemSearchOrder) {
+            params.sort = session.inventoryItemSearchSort
+            params.order = session.inventoryItemSearchOrder
+        }
+
+        if(isFilterApplied) {
+            // filterPane:
             inventoryItemInstanceList = filterService.filter( params, InventoryItem )
             inventoryItemInstanceTotal = filterService.count( params, InventoryItem )
             filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+            // Remember search.
+            session.inventoryItemSearchFilterParams = new LinkedHashMap(filterParams)
+            session.inventoryItemSearchFilter = new LinkedHashMap(params.filter)
+            session.inventoryItemQuickSearch = null
+        }
+        else {
+            // Quick Search:
+            if(!params.quickSearch) params.quickSearch = "all"
+            def result = inventoryItemSearchService.getQuickSearch(params, RCU.getLocale(request))
+            inventoryItemInstanceList = result.inventoryItemList
+            inventoryItemInstanceTotal = result.inventoryItemList.totalCount
+            params.message = result.message
+            filterParams.quickSearch = result.quickSearch
+            // Remember search.
+            session.inventoryItemSearchFilterParams = null
+            session.inventoryItemSearchFilter = null
+            session.inventoryItemQuickSearch = result.quickSearch
         }
 
@@ -145,5 +185,10 @@
                 formatDate(format: "EEE, dd-MMM-yyyy", date: date)
             }
-            String title = "Inventory List."
+
+            String title
+            if(params.quickSearch)
+                title = params.message
+            else
+                title = "Filtered Inventory List."
 
             response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
@@ -152,4 +197,5 @@
                                 "description",
                                 "unitsInStock",
+                                "reorderPoint",
                                 "unitOfMeasure",
                                 "inventoryLocation",
@@ -158,4 +204,5 @@
                                 "description": "Description",
                                 "unitsInStock":"In Stock",
+                                "reorderPoint":"Reorder Point",
                                 "unitOfMeasure": "UOM",
                                 "inventoryLocation": "Location",
@@ -177,10 +224,11 @@
         filterParams.max = params.max
         filterParams.offset = params.offset?.toInteger() ?: 0
-        filterParams.sort = params.sort ?: "id"
-        filterParams.order = params.order ?: "desc"
+        filterParams.sort = params.sort ?: "name"
+        filterParams.order = params.order ?: "asc"
 
         return[ inventoryItemInstanceList: inventoryItemInstanceList,
                 inventoryItemInstanceTotal: inventoryItemInstanceTotal,
-                filterParams: filterParams ]
+                filterParams: filterParams,
+                params: params ]
     } // end search()
 
Index: trunk/grails-app/i18n/messages.properties
===================================================================
--- trunk/grails-app/i18n/messages.properties	(revision 484)
+++ trunk/grails-app/i18n/messages.properties	(revision 485)
@@ -200,4 +200,5 @@
 default.options.text=Options
 default.none.text=None
+default.all.text=All
 
 # Rich UI plugin - Calendar
@@ -287,2 +288,11 @@
 task.search.text.planners.range.none.found=No tasks found in the past week or two weeks ahead.
 task.search.calendar.text.too.many.results=Too many results, only {0} are shown.
+
+# InventoryItemSearch
+inventoryItem.search.text.below.reorder=Bellow Reorder
+inventoryItem.search.text.below.reorder.description=Inventory items at or below reorder point, with reorder enabled.
+inventoryItem.search.text.below.reorder.all=Below Reorder (all)
+inventoryItem.search.text.below.reorder.all.description=Inventory items at or below reorder point, including reorder disabled.
+inventoryItem.search.text.below.reorder.none.found=No inventory items found at or below reorder point.
+inventoryItem.search.text.all.description=All inventory items.
+inventoryItem.search.text.all.none.found=No inventory items found.
Index: trunk/grails-app/services/InventoryItemSearchService.groovy
===================================================================
--- trunk/grails-app/services/InventoryItemSearchService.groovy	(revision 485)
+++ trunk/grails-app/services/InventoryItemSearchService.groovy	(revision 485)
@@ -0,0 +1,95 @@
+/**
+* Service class that encapsulates the business logic for InventoryItem searches.
+*/
+class InventoryItemSearchService {
+
+    boolean transactional = false
+
+    def messageSource
+
+    def paramsMax = 100000
+
+    /**
+    * Selects and returns the correct search results based on the supplied quickSearch.
+    * @param params The request params, may contain params.quickSearch string to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getQuickSearch(params, locale) {
+        def result = [:]
+        result.quickSearch = params.quickSearch ?: "all"
+
+        def getMessage = { Map m ->
+            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
+        }
+
+        switch (result.quickSearch) {
+            case "inventoryBelowReorder":
+                result.inventoryItemList = getInventoryBelowReorder(params)
+                if(result.inventoryItemList.totalCount > 0)
+                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.description")
+                else
+                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.none.found")
+                break
+            case "inventoryBelowReorderAll":
+                result.inventoryItemList = getInventoryBelowReorder(params, false)
+                if(result.inventoryItemList.totalCount > 0)
+                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.all.description")
+                else
+                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.none.found")
+                break
+            default:
+                result.inventoryItemList = getAll(params)
+                if(result.inventoryItemList.totalCount > 0)
+                    result.message = getMessage(code:"inventoryItem.search.text.all.description")
+                else
+                    result.message = getMessage(code:"inventoryItem.search.text.all.none.found")
+                break
+        } // switch.
+
+        // Success.
+        return result
+
+    } // getQuickSearch
+
+    /**
+    * Get all inventory items.
+    * @param params The request params.
+    */
+    def getAll(params) {
+        params.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        params.offset = params?.offset?.toInteger() ?: 0
+        params.sort = params?.sort ?: "name"
+        params.order = params?.order ?: "asc"
+
+        def inventoryItemList = InventoryItem.createCriteria().list(
+            max: params.max,
+            offset: params.offset,
+            sort: params.sort,
+            order: params.order) {
+            } // createCriteria
+    } // getAll
+
+    /**
+    * List inventory items that are below reorder point.
+    * @param params The request params.
+    * @param onlyReorderEnabled Only include items with reorder enabled, defaults to true.
+    */
+    def getInventoryBelowReorder(params, onlyReorderEnabled=true) {
+        params.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        params.offset = params?.offset?.toInteger() ?: 0
+        params.sort = params?.sort ?: "name"
+        params.order = params?.order ?: "asc"
+
+        def inventoryItemList = InventoryItem.createCriteria().list(
+            max: params.max,
+            offset: params.offset,
+            sort: params.sort,
+            order: params.order) {
+                eq("isActive", true)
+                if(onlyReorderEnabled)
+                    eq("enableReorder", true)
+                leProperty("unitsInStock", "reorderPoint")
+            } // createCriteria
+    } // getInventoryBelowReorder
+
+} // end class
Index: trunk/grails-app/views/inventoryItemDetailed/search.gsp
===================================================================
--- trunk/grails-app/views/inventoryItemDetailed/search.gsp	(revision 484)
+++ trunk/grails-app/views/inventoryItemDetailed/search.gsp	(revision 485)
@@ -197,4 +197,29 @@
                         <tr class="prop">
                             <td valign="top" class="name">
+                                <label>Inventory:</label>
+                            </td>
+                            <td valign="top" class="value">
+                                <g:link controller="inventoryItemDetailed"
+                                                action="search"
+                                                params="[quickSearch: 'all']">
+                                                <g:message code="default.all.text" />
+                                </g:link>
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="search"
+                                                params="[quickSearch: 'inventoryBelowReorder']">
+                                                <g:message code="inventoryItem.search.text.below.reorder" />
+                                </g:link> - <g:message code="inventoryItem.search.text.below.reorder.description" />
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="search"
+                                                params="[quickSearch: 'inventoryBelowReorderAll']">
+                                                <g:message code="inventoryItem.search.text.below.reorder.all" />
+                                </g:link> - <g:message code="inventoryItem.search.text.below.reorder.all.description" />
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">
                                 <label>Links:</label>
                             </td>
@@ -204,5 +229,4 @@
                                                 Purchases
                                 </g:link>
-                                <br />
                             </td>
                         </tr>
