Index: trunk/grails-app/controllers/TaskDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/TaskDetailedController.groovy	(revision 712)
+++ trunk/grails-app/controllers/TaskDetailedController.groovy	(revision 713)
@@ -61,4 +61,5 @@
         params.max = Math.min( params.max ? params.max.toInteger() : 100,  1000 )
 
+        // View main data.
         def taskInstanceList = []
         def taskInstanceTotal
@@ -68,10 +69,17 @@
         // Restore search unless a new search is being requested.
         if(!params.quickSearch && !filterParams) {
-            if(session.taskSearchQuickSearch)
-                params.quickSearch = session.taskSearchQuickSearch
-            else if(session.taskSearchFilterParams) {
+            if(session.taskSearchFilterParams) {
                 session.taskSearchFilterParams.each() { params[it.key] = it.value }
                 params.filter = session.taskSearchFilter
                 isFilterApplied = FilterUtils.isFilterApplied(params)
+            }
+        }
+        if(!params.quickSearch) {
+            if(session.taskSearchQuickSearch) {
+                params.quickSearch = session.taskSearchQuickSearch
+                params.person = Person.get(session.taskQuickSearchPersonId.toLong())
+                params.startDate = session.taskQuickSearchStartDate
+                params.endDate = session.taskQuickSearchEndDate
+                params.includeCompleted = session.taskQuickSearchIncludeCompleted
             }
         }
@@ -114,18 +122,24 @@
             session.taskSearchFilterParams = new LinkedHashMap(filterParams)
             session.taskSearchFilter = new LinkedHashMap(params.filter)
-            session.removeAttribute("taskSearchQuickSearch")
         }
         else {
             // Quick Search:
-            if(!params.quickSearch) params.quickSearch = "myTodays"
             def result = taskSearchService.getQuickSearch(params, RCU.getLocale(request))
             taskInstanceList = result.taskInstanceList
             taskInstanceTotal = result.taskInstanceList.totalCount
             params.message = result.message
-            filterParams.quickSearch = result.quickSearch
+            params.quickSearch = result.quickSearch
+            params.person = result.person
+            params.startDate = result.startDate
+            params.endDate = result.endDate
+            params.includeCompleted = result.includeCompleted
             // Remember search.
             session.removeAttribute("taskSearchFilterParams")
             session.removeAttribute("taskSearchFilter")
             session.taskSearchQuickSearch = result.quickSearch
+            session.taskQuickSearchPersonId = result.person.id
+            session.taskQuickSearchStartDate = result.startDate
+            session.taskQuickSearchEndDate = result.endDate
+            session.taskQuickSearchIncludeCompleted = result.includeCompleted
         }
 
@@ -181,5 +195,6 @@
                         filterParams: filterParams,
                         params: params,
-                        associatedPropertyValues: associatedPropertyValues ]
+                        associatedPropertyValues: associatedPropertyValues,
+                        quickSearchSelection: taskSearchService.quickSearchSelection]
 
     } // search
@@ -206,10 +221,17 @@
         // Restore search unless a new search is being requested.
         if(!params.quickSearch && !filterParams) {
-            if(session.taskSearchCalendarQuickSearch)
-                params.quickSearch = session.taskSearchCalendarQuickSearch
-            else if(session.taskSearchCalendarFilterParams) {
+            if(session.taskSearchCalendarFilterParams) {
                 session.taskSearchCalendarFilterParams.each() { params[it.key] = it.value }
                 params.filter = session.taskSearchCalendarFilter
                 isFilterApplied = FilterUtils.isFilterApplied(params)
+            }
+        }
+        if(!params.quickSearch) {
+            if(session.taskSearchCalendarQuickSearch) {
+                params.quickSearch = session.taskSearchCalendarQuickSearch
+                params.person = Person.get(session.taskCalendarQuickSearchPersonId.toLong())
+                params.startDate = session.taskCalendarQuickSearchStartDate
+                params.endDate = session.taskCalendarQuickSearchEndDate
+                params.includeCompleted = session.taskCalendarQuickSearchIncludeCompleted
             }
         }
@@ -250,5 +272,4 @@
             session.taskSearchCalendarFilterParams = new LinkedHashMap(filterParams)
             session.taskSearchCalendarFilter = new LinkedHashMap(params.filter)
-            session.removeAttribute("taskSearchCalendarQuickSearch")
         }
         else {
@@ -258,9 +279,17 @@
             taskInstanceTotal = result.taskInstanceList.totalCount
             params.message = result.message
-            filterParams.quickSearch = result.quickSearch
+            params.quickSearch = result.quickSearch
+            params.person = result.person
+            params.startDate = result.startDate
+            params.endDate = result.endDate
+            params.includeCompleted = result.includeCompleted
             // Remember search.
             session.removeAttribute("taskSearchCalendarFilterParams")
             session.removeAttribute("taskSearchCalendarFilter")
             session.taskSearchCalendarQuickSearch = result.quickSearch
+            session.taskCalendarQuickSearchPersonId = result.person.id
+            session.taskCalendarQuickSearchStartDate = result.startDate
+            session.taskCalendarQuickSearchEndDate = result.endDate
+            session.taskCalendarQuickSearchIncludeCompleted = result.includeCompleted
         }
 
@@ -329,5 +358,6 @@
                         nextMonth: calendarMonthControls.nextMonth,
                         previousYear: calendarMonthControls.previousYear,
-                        nextYear: calendarMonthControls.nextYear]
+                        nextYear: calendarMonthControls.nextYear,
+                        quickSearchSelection: taskSearchService.quickSearchSelection]
 
     } // searchCalendar
Index: trunk/grails-app/i18n/messages.properties
===================================================================
--- trunk/grails-app/i18n/messages.properties	(revision 712)
+++ trunk/grails-app/i18n/messages.properties	(revision 713)
@@ -374,4 +374,9 @@
 #
 
+task.search.include.completed=Incl. Completed
+task.search.include.completed.help=Include completed tasks in the results.
+
+task.search.text.all.tasks=All Tasks
+task.search.text.all.tasks.help=All tasks that are not in the trash. Tasks in the trash must be explicitly requested in the advanced search.
 task.search.text.all.tasks.message=All tasks for {0}.
 task.search.text.all.tasks.none.found=No tasks found for {0}.
@@ -379,4 +384,20 @@
 task.search.text.all.tasks.between.none.found=No tasks found between {0} and {1}.
 
+task.search.text.budget.planned=Budget Planned
+task.search.text.budget.planned.help=Tasks with a budget status of 'Planned'.
+task.search.text.budget.planned.message=Tasks with a budget status of 'Planned' for {0}.
+task.search.text.budget.planned.none.found=No tasks found with a budget status of 'Planned' for {0}.
+task.search.text.budget.planned.between.message=Tasks with a budget status of 'Planned' between {0} and {1}.
+task.search.text.budget.planned.between.none.found=No tasks found with a budget status of 'Planned' between {0} and {1}.
+
+task.search.text.budget.unplanned=Budget Unplanned
+task.search.text.budget.unplanned.help=Tasks with a budget status of 'Unplanned'.
+task.search.text.budget.unplanned.message=Tasks with a budget status of 'Unplanned' for {0}.
+task.search.text.budget.unplanned.none.found=No tasks found with a budget status of 'Unplanned' for {0}.
+task.search.text.budget.unplanned.between.message=Tasks with a budget status of 'Unplanned' between {0} and {1}.
+task.search.text.budget.unplanned.between.none.found=No tasks found with a budget status of 'Unplanned' between {0} and {1}.
+
+task.search.text.persons.tasks=Person's Tasks
+task.search.text.persons.tasks.help=Approved tasks that a person is assigned to.
 task.search.text.persons.tasks.message=Tasks for {0} on {1}.
 task.search.text.persons.tasks.none.found=No tasks found for {0} on {1}.
@@ -386,21 +407,12 @@
 task.search.text.my.todays=Today
 task.search.text.my.todays.description=My tasks and approved tasks that I am assigned to.
-task.search.text.my.yesterdays=Yesterday
-task.search.text.my.tomorrows=Tomorrow
-task.search.text.my.past.week=Past Week
-task.search.text.todays=Today
-task.search.text.todays.description=All tasks that are not in the trash bin.
-task.search.text.yesterdays=Yesterday
-task.search.text.tomorrows=Tomorrow
-task.search.text.past.week=Past Week
-task.search.text.budget.unplanned=Unplanned Tasks
-task.search.text.budget.unplanned.message=Tasks with budget status of 'Unplanned' between {0} and {1}.
-task.search.text.budget.unplanned.none.found=No tasks found with budget status of 'Unplanned' between {0} and {1}.
-task.search.text.budget.planned=Planned Tasks
-task.search.text.budget.planned.description=Task with budget status of Planned, in the past week.
-task.search.text.budget.planned.message=Tasks with budget status of 'Planned' between {0} and {1}.
-task.search.text.budget.planned.none.found=No tasks found with budget status of 'Planned' between {0} and {1}.
-task.search.text.planners.range=Planners Range
-task.search.text.planners.range.description=Tasks in the past week and two weeks ahead.
+
+task.search.text.persons.immediate.callouts=Person's Callouts
+task.search.text.persons.immediate.callouts.help=Immediate callouts by person (lead person or created by).
+task.search.text.persons.immediate.callouts.message=Immediate callouts for {0} on {1}.
+task.search.text.persons.immediate.callouts.none.found=No immediate callouts found for {0} on {1}.
+task.search.text.persons.immediate.callouts.between.message=Immediate callouts for {0} between {1} and {2}.
+task.search.text.persons.immediate.callouts.between.none.found=No immediate callouts found for {0} between {1} and {2}.
+
 task.search.calendar.text.too.many.results=Too many results, only {0} are shown.
 task.search.text.work.done=Work Done
Index: trunk/grails-app/services/TaskSearchService.groovy
===================================================================
--- trunk/grails-app/services/TaskSearchService.groovy	(revision 712)
+++ trunk/grails-app/services/TaskSearchService.groovy	(revision 713)
@@ -1,2 +1,3 @@
+import net.kromhouts.HqlBuilder
 import grails.orm.PagedResultList
 import org.hibernate.FetchMode as FM
@@ -16,4 +17,14 @@
 
     def paramsMax = 100000
+
+    // Be sure to update taskQuickSearchPane.js if quickSearchSelection is changed.
+    def getQuickSearchSelection() {
+        [ 'allTasks': g.message(code: 'task.search.text.all.tasks'),
+        'budgetPlanned': g.message(code: 'task.search.text.budget.planned'),
+        'budgetUnplanned': g.message(code: 'task.search.text.budget.unplanned'),
+        'personsImmediateCallouts': g.message(code: 'task.search.text.persons.immediate.callouts'),
+        'personsTasks': g.message(code: 'task.search.text.persons.tasks')
+        ]
+    }
 
     /**
@@ -22,9 +33,29 @@
     * @param locale The locale to use when generating result.message.
     */
-    def getQuickSearch(params, locale) {
+    def getQuickSearch(params = [:], locale) {
         def result = [:]
-        result.quickSearch = params.quickSearch ?: "plannersRange"
-
-        def currentUser = authService.currentUser
+        result.quickSearch = params.quickSearch ?: "personsTasks"
+        if(params.person)
+            result.person = Person.get(params.person.id.toLong())
+        else
+            result.person = authService.currentUser
+        result.startDate = params.startDate ?: dateUtilService.today
+        result.endDate = params.endDate ?: dateUtilService.today
+        // Auto swap date range.
+        if(result.startDate > result.endDate) {
+            def tempStartDate = result.startDate
+            result.startDate = result.endDate
+            result.endDate = tempStartDate
+        }
+        result.includeCompleted = params.includeCompleted = params.includeCompleted ? true:false
+
+        def getMessage = { Map m ->
+            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
+        }
+
+        def formatted = { Date d ->
+            g.formatDate(format: "EEE, dd-MMM-yyyy", date: d)
+        }
+
         def startOfToday = dateUtilService.today
         def startOfYesterday = dateUtilService.yesterday
@@ -32,115 +63,174 @@
         def oneWeekAgo = dateUtilService.oneWeekAgo
 
-        def formattedStartOfToday = g.formatDate(format: "EEE, dd-MMM-yyyy", date: startOfToday)
-        def formattedStartOfYesterday = g.formatDate(format: "EEE, dd-MMM-yyyy", date: startOfYesterday)
-        def formattedStartOfTomorrow = g.formatDate(format: "EEE, dd-MMM-yyyy", date: startOfTomorrow)
-        def formattedOneWeekAgo = g.formatDate(format: "EEE, dd-MMM-yyyy", date: oneWeekAgo)
-
-        def getMessage = { Map m ->
-            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
+        def formattedStartOfToday = formatted(startOfToday)
+        def formattedStartOfYesterday = formatted(startOfYesterday)
+        def formattedStartOfTomorrow = formatted(startOfTomorrow)
+        def formattedOneWeekAgo = formatted(oneWeekAgo)
+
+        def allTasks = {
+            result.taskInstanceList = getTasks(params, result.startDate, result.endDate+1)
+            if(result.taskInstanceList.totalCount > 0) {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.all.tasks.message",
+                                                                    args:[ formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.all.tasks.between.message",
+                                                                    args:[ formatted(result.startDate), formatted(result.endDate) ])
+            }
+            else {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.all.tasks.none.found",
+                                                                    args:[ formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.all.tasks.between.none.found",
+                                                                    args:[ formatted(result.startDate), formatted(result.endDate) ])
+            }
+
+        }
+
+        def personsTasks = {
+            result.taskInstanceList = getPersonsTasks(params, result.person, result.startDate, result.endDate+1)
+            if(result.taskInstanceList.totalCount > 0) {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.persons.tasks.message",
+                                                                    args:[ result.person, formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.persons.tasks.between.message",
+                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
+            }
+            else {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.persons.tasks.none.found",
+                                                                    args:[ result.person, formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.persons.tasks.between.none.found",
+                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
+            }
+
+        }
+
+        def personsImmediateCallouts = {
+            result.taskInstanceList = getPersonsImmediateCallouts(params, result.person, result.startDate, result.endDate+1)
+            if(result.taskInstanceList.totalCount > 0) {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.message",
+                                                                    args:[ result.person, formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.between.message",
+                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
+            }
+            else {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.none.found",
+                                                                    args:[ result.person, formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.between.none.found",
+                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
+            }
+
         }
 
         switch (result.quickSearch) {
             case "myTodays":
-                result.taskInstanceList = getPersonsTasks(params)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.persons.tasks.message",
-                                                                    args:[currentUser, formattedStartOfToday])
-                else
-                    result.message = getMessage(code:"task.search.text.persons.tasks.none.found",
-                                                                    args:[currentUser, formattedStartOfToday])
+                result.quickSearch = "personsTasks"
+                result.startDate = startOfToday
+                result.endDate = startOfToday
+                personsTasks()
                 break
             case "myYesterdays":
-                result.taskInstanceList = getPersonsTasks(params, currentUser, startOfYesterday, startOfToday)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.persons.tasks.message",
-                                                                    args:[currentUser, formattedStartOfYesterday])
-                else
-                    result.message = getMessage(code:"task.search.text.persons.tasks.none.found",
-                                                                    args:[currentUser, formattedStartOfYesterday])
+                result.quickSearch = "personsTasks"
+                result.startDate = startOfYesterday
+                result.endDate = startOfYesterday
+                personsTasks()
                 break
             case "myTomorrows":
-                result.taskInstanceList = getPersonsTasks(params, currentUser, startOfTomorrow, startOfTomorrow+1)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.persons.tasks.message",
-                                                                    args:[currentUser, formattedStartOfTomorrow])
-                else
-                    result.message = getMessage(code:"task.search.text.persons.tasks.none.found",
-                                                                    args:[currentUser, formattedStartOfTomorrow])
+                result.quickSearch = "personsTasks"
+                result.startDate = startOfTomorrow
+                result.endDate = startOfTomorrow
+                personsTasks()
                 break
             case "myPastWeek":
-                result.taskInstanceList = getPersonsTasks(params, currentUser, oneWeekAgo, startOfTomorrow)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.persons.tasks.between.message",
-                                                                    args:[currentUser, formattedOneWeekAgo, formattedStartOfToday])
-                else
-                    result.message = getMessage(code:"task.search.text.persons.tasks.between.none.found",
-                                                                    args:[currentUser, formattedOneWeekAgo, formattedStartOfToday])
+                result.quickSearch = "personsTasks"
+                result.startDate = oneWeekAgo
+                result.endDate = startOfToday
+                personsTasks()
+                break
+            case "personsTasks":
+                personsTasks()
+                break
+            case "personsImmediateCallouts":
+                personsImmediateCallouts()
                 break
             case "todays":
-                result.taskInstanceList = getTasks(params)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.all.tasks.message",
-                                                                    args:[formattedStartOfToday])
-                else
-                    result.message = getMessage(code:"task.search.text.all.tasks.none.found",
-                                                                    args:[formattedStartOfToday])
+                result.quickSearch = "allTasks"
+                result.startDate = startOfToday
+                result.endDate = startOfToday
+                allTasks()
                 break
             case "yesterdays":
-                result.taskInstanceList = getTasks(params, startOfYesterday, startOfToday)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.all.tasks.message",
-                                                                    args:[formattedStartOfYesterday])
-                else
-                    result.message = getMessage(code:"task.search.text.all.tasks.none.found",
-                                                                    args:[formattedStartOfYesterday])
+                result.quickSearch = "allTasks"
+                result.startDate = startOfYesterday
+                result.endDate = startOfToday
+                allTasks()
                 break
             case "tomorrows":
-                result.taskInstanceList = getTasks(params, startOfTomorrow, startOfTomorrow+1)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.all.tasks.message",
-                                                                    args:[formattedStartOfTomorrow])
-                else
-                    result.message = getMessage(code:"task.search.text.all.tasks.none.found",
-                                                                    args:[formattedStartOfTomorrow])
+                result.quickSearch = "allTasks"
+                result.startDate = startOfTomorrow
+                result.endDate = startOfTomorrow+1
+                allTasks()
                 break
             case "pastWeek":
-                result.taskInstanceList = getTasks(params, oneWeekAgo, startOfTomorrow)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.all.tasks.between.message",
-                                                                    args:[formattedOneWeekAgo, formattedStartOfToday])
-                else
-                    result.message = getMessage(code:"task.search.text.all.tasks.between.none.found",
-                                                                    args:[formattedOneWeekAgo, formattedStartOfToday])
+                result.quickSearch = "allTasks"
+                result.startDate = oneWeekAgo
+                result.endDate = startOfTomorrow
+                allTasks()
+                break
+            case "allTasks":
+                allTasks()
                 break
             case "budgetUnplanned":
-                result.taskInstanceList = getBudgetTasks(params, TaskBudgetStatus.read(1), oneWeekAgo, startOfTomorrow)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.budget.unplanned.message",
-                                                                    args:[formattedOneWeekAgo, formattedStartOfToday])
-                else
-                    result.message = getMessage(code:"task.search.text.budget.unplanned.none.found",
-                                                                    args:[formattedOneWeekAgo, formattedStartOfToday])
+                result.taskInstanceList = getBudgetTasks(params, TaskBudgetStatus.read(1), result.startDate, result.endDate+1)
+                if(result.taskInstanceList.totalCount > 0) {
+                    if(result.startDate == result.endDate)
+                        result.message = getMessage(code:"task.search.text.budget.unplanned.message",
+                                                                        args:[ formatted(result.startDate) ])
+                    else
+                        result.message = getMessage(code:"task.search.text.budget.unplanned.between.message",
+                                                                        args:[ formatted(result.startDate), formatted(result.endDate) ])
+                }
+                else {
+                    if(result.startDate == result.endDate)
+                        result.message = getMessage(code:"task.search.text.budget.unplanned.none.found",
+                                                                        args:[ formatted(result.startDate) ])
+                    else
+                        result.message = getMessage(code:"task.search.text.budget.unplanned.between.none.found",
+                                                                        args:[ formatted(result.startDate), formatted(result.endDate) ])
+                }
                 break
             case "budgetPlanned":
-                result.taskInstanceList = getBudgetTasks(params, TaskBudgetStatus.read(2), oneWeekAgo, startOfTomorrow)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.budget.planned.message",
-                                                                    args:[formattedOneWeekAgo, formattedStartOfToday])
-                else
-                    result.message = getMessage(code:"task.search.text.budget.planned.none.found",
-                                                                    args:[formattedOneWeekAgo, formattedStartOfToday])
+                result.taskInstanceList = getBudgetTasks(params, TaskBudgetStatus.read(2), result.startDate, result.endDate+1)
+                if(result.taskInstanceList.totalCount > 0) {
+                    if(result.startDate == result.endDate)
+                        result.message = getMessage(code:"task.search.text.budget.planned.message",
+                                                                        args:[ formatted(result.startDate) ])
+                    else
+                        result.message = getMessage(code:"task.search.text.budget.planned.between.message",
+                                                                        args:[ formatted(result.startDate), formatted(result.endDate) ])
+                }
+                else {
+                    if(result.startDate == result.endDate)
+                        result.message = getMessage(code:"task.search.text.budget.planned.none.found",
+                                                                        args:[ formatted(result.startDate) ])
+                    else
+                        result.message = getMessage(code:"task.search.text.budget.planned.between.none.found",
+                                                                        args:[ formatted(result.startDate), formatted(result.endDate) ])
+                }
                 break
             default:
                 //case "plannersRange":
-                result.taskInstanceList = getTasks(params, oneWeekAgo, startOfToday+15)
-                if(result.taskInstanceList.totalCount > 0)
-                    result.message = getMessage(code:"task.search.text.all.tasks.between.message",
-                                                                    args:[formattedOneWeekAgo,
-                                                                            g.formatDate(format: "EEE, dd-MMM-yyyy", date: startOfToday+14)])
-                else
-                    result.message = getMessage(code:"task.search.text.all.tasks.between.none.found",
-                                                                    args:[formattedOneWeekAgo,
-                                                                            g.formatDate(format: "EEE, dd-MMM-yyyy", date: startOfToday+14)])
+                result.quickSearch = "allTasks"
+                result.startDate = oneWeekAgo
+                result.endDate = startOfToday+15
+                allTasks()
                 break
         } // switch.
@@ -202,7 +292,7 @@
     */
     def getPersonsTasks(params, person=null, startDate=null, endDate=null) {
-        def paginateParams = [:]
-        paginateParams.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
-        paginateParams.offset = params?.offset?.toInteger() ?: 0
+
+        def max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        def offset = params?.offset?.toInteger() ?: 0
 
         def orderBy = ''
@@ -212,50 +302,102 @@
             def sort = "task." + params.sort
             def order = (params.order == "asc") ? "asc" : "desc"
-            orderBy = " order by " + sort + ' ' + order
-        }
-        else
-            orderBy = " order by task.taskStatus, task.taskPriority, task.targetStartDate"
-
-        def namedParams = [:]
-        namedParams.person = person ?: authService.currentUser
-        namedParams.startDate = startDate ?: dateUtilService.today
-        namedParams.endDate = endDate ?: dateUtilService.tomorrow
-
-        def baseQuery = "from Task as task \
-                                        left join task.assignedPersons as assignedPersonOfTask \
-                                        left join assignedPersonOfTask.person as assignedPerson \
-                                        left join task.assignedGroups as assignedGroupOfTask \
-                                        left join assignedGroupOfTask.personGroup as personGroup \
-                                        left join personGroup.persons as assignedPersonViaGroup \
-                                        left join task.taskModifications as taskModification \
-                                        left join taskModification.person as createdBy \
-                                        left join taskModification.taskModificationType as taskModificationType \
-                                        where (task.trash = false \
-                                                    and task.targetStartDate < :endDate \
-                                                    and task.targetCompletionDate >= :startDate \
-                                                    and ( \
-                                                        (taskModificationType.id = 1 \
-                                                        and createdBy = :person \
-                                                        and task.leadPerson = :person) \
-                                                        or ( \
-                                                            task.approved = true \
-                                                            and ( \
-                                                                task.leadPerson = :person \
-                                                                or assignedPerson = :person \
-                                                                or assignedPersonViaGroup = :person \
-                                                            ) \
-                                                        ) \
-                                                    ) \
-                                        )"
-
-        def searchQuery = "select distinct task " + baseQuery + orderBy
-        def list = Task.executeQuery(searchQuery, namedParams, paginateParams)
-
-        def countQuery = "select count(distinct task) as taskCount " + baseQuery
-        def totalCount = Task.executeQuery(countQuery, namedParams)[0].toInteger()
+            orderBy = "by " + sort + ' ' + order
+        }
+        else
+            orderBy = "by task.taskStatus, task.taskPriority, task.targetStartDate"
+
+        def q = new HqlBuilder().query {
+
+            select 'count(distinct task) as taskCount'
+            from 'Task as task',
+                    'left join task.assignedPersons as assignedPersonOfTask',
+                    'left join assignedPersonOfTask.person as assignedPerson',
+                    'left join task.assignedGroups as assignedGroupOfTask',
+                    'left join assignedGroupOfTask.personGroup as personGroup',
+                    'left join personGroup.persons as assignedPersonViaGroup',
+                    'left join task.taskModifications as taskModification',
+                    'left join taskModification.person as createdBy',
+                    'left join taskModification.taskModificationType as taskModificationType'
+            where 'task.trash = false'
+                    and 'task.targetStartDate < :endDate'
+                    and 'task.targetCompletionDate >= :startDate'
+                    if(!params.includeCompleted) {
+                        and 'task.taskStatus.id != 3' // Complete.
+                    }
+                    and {
+                        where '(taskModificationType.id = 1 and createdBy = :person and task.leadPerson = :person)' // Created.
+                        or '(task.approved = true and (task.leadPerson = :person or assignedPerson = :person or assignedPersonViaGroup = :person))'
+                    }
+        }
+
+        q.namedParams.person = person ?: authService.currentUser
+        q.namedParams.startDate = startDate ?: dateUtilService.today
+        q.namedParams.endDate = endDate ?: dateUtilService.tomorrow
+
+        def totalCount = Task.executeQuery(q.query, q.namedParams)[0].toInteger()
+
+        q.select = "distinct task"
+        q.order = orderBy
+        def list = Task.executeQuery(q.query, q.namedParams, q.paginateParams)
 
         def taskInstanceList = new PagedResultList(list, totalCount)
         return taskInstanceList
     } // getPersonsTasks()
+
+    /**
+    * Get a person's immediateCallout tasks, by default all users and today's tasks.
+    * @param params The request params.
+    * @param person The person to get tasks for, defaults to null and therefore all immediateCallouts.
+    * @param startDate The start date to get tasks for, defaults to the start of today and is inclusive (greater than or equal to).
+    * @param endDate The end date to get tasks for, defaults to the start of tomorrow and is exclusive (less than).
+    */
+    def getPersonsImmediateCallouts(params, person=null, startDate=null, endDate=null) {
+
+        def max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        def offset = params?.offset?.toInteger() ?: 0
+
+        def orderBy = ''
+        if(params.sort?.contains('.')) // protect against filterpane bug.
+            params.sort = null
+        if(params.sort && params.order) {
+            def sort = "task." + params.sort
+            def order = (params.order == "asc") ? "asc" : "desc"
+            orderBy = "by " + sort + ' ' + order
+        }
+        else
+            orderBy = "by task.taskStatus, task.taskPriority, task.targetStartDate"
+
+        def q = new HqlBuilder().query {
+
+            select 'count(distinct task) as taskCount'
+            from 'Task as task',
+                    'left join task.taskModifications as taskModification',
+                    'left join taskModification.person as createdBy',
+                    'left join taskModification.taskModificationType as taskModificationType'
+            where 'task.taskType.id = 1' // Immediate Callout.
+                    and 'task.targetStartDate < :endDate'
+                    and 'task.targetCompletionDate >= :startDate'
+                    if(!params.includeCompleted) {
+                        and 'task.taskStatus.id != 3' // Complete.
+                    }
+                    if(person) {
+                        namedParams.person = person
+                        and '( (taskModificationType.id = 1 and createdBy = :person) or task.leadPerson = :person)' // Created or Lead Person.
+                    }
+                    and 'task.trash = false'
+        }
+
+        q.namedParams.startDate = startDate ?: dateUtilService.today
+        q.namedParams.endDate = endDate ?: dateUtilService.tomorrow
+
+        def totalCount = Task.executeQuery(q.query, q.namedParams)[0].toInteger()
+
+        q.select = "distinct task"
+        q.order = orderBy
+        def list = Task.executeQuery(q.query, q.namedParams, q.paginateParams)
+
+        def taskInstanceList = new PagedResultList(list, totalCount)
+        return taskInstanceList
+    } // getPersonsImmediateCallouts()
 
     /**
Index: trunk/grails-app/views/taskDetailed/_quickSearchPane.gsp
===================================================================
--- trunk/grails-app/views/taskDetailed/_quickSearchPane.gsp	(revision 712)
+++ trunk/grails-app/views/taskDetailed/_quickSearchPane.gsp	(revision 713)
@@ -2,36 +2,35 @@
 <div class="overlayPane" id="searchPane" style="display:none;">
     <h2>Quick Search</h2>
-    <g:form method="post" id="searchForm" name="searchForm" >
+
+    <g:form method="post" controller="taskDetailed">
         <table>
             <tbody>
 
                 <tr class="prop">
-                    <td valign="top" class="name">
-                        <label>My Tasks:</label>
-                    </td>
+                    <td valign="top" class="name">Select:</td>
                     <td valign="top" class="value">
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'myTodays']">
-                                        <g:message code="task.search.text.my.todays" />
-                        </g:link> - <g:message code="task.search.text.my.todays.description" />
-                        <br />
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'myYesterdays']">
-                                        <g:message code="task.search.text.my.yesterdays" />
-                        </g:link>
-                        <br />
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'myTomorrows']">
-                                        <g:message code="task.search.text.my.tomorrows" />
-                        </g:link>
-                        <br />
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'myPastWeek']">
-                                        <g:message code="task.search.text.my.past.week" />
-                        </g:link>
+                        <g:select optionKey="key"
+                                            optionValue="value"
+                                            from="${quickSearchSelection}"
+                                            name="quickSearch"
+                                            id="quickSearchSelect"
+                                            value="${params.quickSearch}">
+                        </g:select>
+
+                            <span id="allTasksHelp">
+                                <g:helpBalloon class="helpballoon" code="task.search.text.all.tasks" />
+                            </span>
+                            <span id="budgetPlannedHelp">
+                                <g:helpBalloon class="helpballoon" code="task.search.text.budget.planned" />
+                            </span>
+                            <span id="budgetUnplannedHelp">
+                                <g:helpBalloon class="helpballoon" code="task.search.text.budget.unplanned" />
+                            </span>
+                            <span id="personsTasksHelp">
+                                <g:helpBalloon class="helpballoon" code="task.search.text.persons.tasks" />
+                            </span>
+                            <span id="personsImmediateCalloutsHelp">
+                                <g:helpBalloon class="helpballoon" code="task.search.text.persons.immediate.callouts" />
+                            </span>
                     </td>
                 </tr>
@@ -39,72 +38,41 @@
                 <tr class="prop">
                     <td valign="top" class="name">
-                        <label>All Tasks:</label>
+                        <label for="date">Between:</label>
                     </td>
                     <td valign="top" class="value">
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'todays']">
-                                        <g:message code="task.search.text.todays" />
-                        </g:link> - <g:message code="task.search.text.todays.description" />
-                        <br />
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'yesterdays']">
-                                        <g:message code="task.search.text.yesterdays" />
-                        </g:link>
-                        <br />
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'tomorrows']">
-                                        <g:message code="task.search.text.tomorrows" />
-                        </g:link>
-                        <br />
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'pastWeek']">
-                                        <g:message code="task.search.text.past.week" />
-                        </g:link>
-                        <br />
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'plannersRange']">
-                                        <g:message code="task.search.text.planners.range" />
-                        </g:link> - <g:message code="task.search.text.planners.range.description" />
+                        <richui:dateChooser name="startDate" format="dd-MM-yyyy" value="${params.startDate}" />
+                        and
+                        <richui:dateChooser name="endDate" format="dd-MM-yyyy" value="${params.endDate}" />
                     </td>
                 </tr>
 
-                <tr class="prop">
+                <tr class="prop" style="height:2.7em;">
                     <td valign="top" class="name">
-                        <label>Budget:</label>
+                        <label for="person.id" id="personLabel">Person:</label>
                     </td>
                     <td valign="top" class="value">
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'budgetPlanned']">
-                                        <g:message code="task.search.text.budget.planned" />
-                        </g:link> - <g:message code="task.search.text.budget.planned.description" />
-                        <br />
-                        <g:link controller="taskDetailed"
-                                        action="${actionName}"
-                                        params="[quickSearch: 'budgetUnplanned']">
-                                        <g:message code="task.search.text.budget.unplanned" />
-                        </g:link>
+                        <div id="personSelection">
+                            <g:select optionKey="id"
+                                                from="${Person.findAllByIsActive(true).sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }}"
+                                                name="person.id"
+                                                value="${params.person?.id}"
+                                                id="personSelector">
+                            </g:select>
+                        </div>
                     </td>
                 </tr>
 
-                <tr class="prop">
+                <tr class="prop" style="height:2.7em;">
                     <td valign="top" class="name">
-                        <label>Links:</label>
+                        <label for="includeCompleted" id="completedLabel">Incl. Completed:</label>
                     </td>
                     <td valign="top" class="value">
-                        <g:link controller="taskDetailed"
-                                        action="workDone">
-                                        <g:message code="task.search.text.work.done" />
-                        </g:link> - <g:message code="task.search.text.work.done.description" />
-                        <br />
-                        <g:link controller="taskDetailed"
-                                        action="workLoad">
-                                        <g:message code="task.search.text.work.load" />
-                        </g:link> - <g:message code="task.search.text.work.load.description" />
+                        <div id="completedSelection">
+                            <g:checkBox name="includeCompleted"
+                                                    value="${params.includeCompleted}"
+                                                    id="completedSelector">
+                            </g:checkBox>
+                            <g:helpBalloon class="helpballoon" code="task.search.include.completed" />
+                        </div>
                     </td>
                 </tr>
@@ -112,9 +80,48 @@
             </tbody>
         </table>
+
         <div class="buttons">
             <span class="button">
+                <g:actionSubmit class="save" value="Update" action="${actionName}" />
                 <g:actionSubmit class="cancel" value="${g.message(code:'fp.tag.filterPane.button.cancel.text', default:'Cancel')}" onclick="return hideElement('searchPane');" />
             </span>
         </div>
     </g:form>
+
+    <table>
+        <tbody>
+            <tr class="prop">
+                <td valign="top" class="name">
+                    <label>My Tasks:</label>
+                </td>
+                <td valign="top" class="value">
+                    <g:link controller="taskDetailed"
+                                    action="${actionName}"
+                                    params="[quickSearch: 'myTodays']">
+                                    <g:message code="task.search.text.my.todays" />
+                    </g:link> - <g:message code="task.search.text.my.todays.description" />
+                    <br />
+                </td>
+            </tr>
+
+            <tr class="prop">
+                <td valign="top" class="name">
+                    <label>Links:</label>
+                </td>
+                <td valign="top" class="value">
+                    <g:link controller="taskDetailed"
+                                    action="workDone">
+                                    <g:message code="task.search.text.work.done" />
+                    </g:link> - <g:message code="task.search.text.work.done.description" />
+                    <br />
+                    <g:link controller="taskDetailed"
+                                    action="workLoad">
+                                    <g:message code="task.search.text.work.load" />
+                    </g:link> - <g:message code="task.search.text.work.load.description" />
+                </td>
+            </tr>
+
+        </tbody>
+    </table>
+
 </div> <!-- end search pane -->
Index: trunk/grails-app/views/taskDetailed/search.gsp
===================================================================
--- trunk/grails-app/views/taskDetailed/search.gsp	(revision 712)
+++ trunk/grails-app/views/taskDetailed/search.gsp	(revision 713)
@@ -7,4 +7,6 @@
         <nav:resources override="true"/>
         <export:resource />
+        <resource:dateChooser />
+        <g:javascript src="taskQuickSearchPane.js" />
     </head>
     <body>
Index: trunk/grails-app/views/taskDetailed/searchCalendar.gsp
===================================================================
--- trunk/grails-app/views/taskDetailed/searchCalendar.gsp	(revision 712)
+++ trunk/grails-app/views/taskDetailed/searchCalendar.gsp	(revision 713)
@@ -8,4 +8,6 @@
         <resource:calendarMonthView  skin="calendarmonthviewCustom"/>
         <export:resource />
+        <resource:dateChooser />
+        <g:javascript src="taskQuickSearchPane.js" />
     </head>
     <body>
Index: trunk/web-app/js/taskQuickSearchPane.js
===================================================================
--- trunk/web-app/js/taskQuickSearchPane.js	(revision 713)
+++ trunk/web-app/js/taskQuickSearchPane.js	(revision 713)
@@ -0,0 +1,41 @@
+
+function updateQuickSearchSelection() {
+    var personsTasksSelectionIds = ['personLabel', 'personSelection', 'completedLabel', 'completedSelection'];
+    var helpBalloonSpanIds = ['allTasksHelp', 'budgetPlannedHelp', 'budgetUnplannedHelp', 'personsTasksHelp', 'personsImmediateCalloutsHelp'];
+    var val = $("quickSearchSelect").value;
+
+    $A(HelpBalloon._balloons).invoke('hide'); // Hide any open balloons.
+    helpBalloonSpanIds.each(Element.hide); // Hide all help icons.
+
+    switch(val)
+    {
+        case 'allTasks':
+            showUtil('allTasksHelp');
+            hideArrayUtil(personsTasksSelectionIds);
+            break;
+        case 'budgetPlanned':
+            showUtil('budgetPlannedHelp');
+            hideArrayUtil(personsTasksSelectionIds);
+            break;
+        case 'budgetUnplanned':
+            showUtil('budgetUnplannedHelp');
+            hideArrayUtil(personsTasksSelectionIds);
+            break;
+        case 'personsTasks':
+            showUtil('personsTasksHelp');
+            showArrayUtil(personsTasksSelectionIds);
+            break;
+        case 'personsImmediateCallouts':
+            showUtil('personsImmediateCalloutsHelp');
+            showArrayUtil(personsTasksSelectionIds);
+            break;
+    }
+
+}
+
+Event.observe(window, 'load', function() {
+    updateQuickSearchSelection(); // Initial page load.
+    $A(HelpBalloon._balloons).invoke('show'); // Work around for offset balloon when using a pane in IE.
+    $A(HelpBalloon._balloons).invoke('hide'); // Work around for offset balloon when using a pane in IE.
+    $("quickSearchSelect").observe('change', updateQuickSearchSelection); // Register onchange handler.
+});
