Sorry for all the email
I have created a patch (attached). As far as I can tell, it works in
windows. I can't add all the columns to the task tree view, but it
works well enough on windows.
Your new changes have effected the code, but it isn't tramatic. See the
comments in the code for potential issues.
I also am using eclipse tasks (FIXME: cz are mine).
I am going on vacation soon and I don't want to have to come back to it.
The feature seems to work well, but it could be tuned a little. It
definitely reduces the number of mouse clicks that I need.
Carl
Carl Zmola wrote:
> Frank,
>
> I just realized that the TaskEditorPage was removed.
> I think the subject page should be an editor page, but I have added the
> needed fields and methods to it temporarily.
>
> I can't proceed testing right now until the windows column header issue
> is fixed.
> If you have a workaround, let me know and I will continue testing. I
> want to get this fix into the tree quickly before too much else changes.
>
> Carl
>
> Carl Zmola wrote:
>
>> Frank,
>>
>> The editor;py changes have thrown me for a loop.
>> Before all task editor pages were of type: TaskEditorPage
>> Now the subject page isn't even an EditorPage.
>> Is this a mistake?
>>
>> I have some code and date that go into the EditorPage.
>>
>> An editor page knows what fields are contained in it, so it has a
>> _fieldMap
>> In addition, they all have a setFocusForField and containsField method.
>> I can add these to Subject page manually, but it seems like the subject
>> page should be an editor page.
>>
>> Is TaskEditorPage going to go away entirely?
>>
>>
>>
>
>
Index: taskcoachlib/gui/dialog/editor.py
===================================================================
--- taskcoachlib/gui/dialog/editor.py (revision 1174)
+++ taskcoachlib/gui/dialog/editor.py (working copy)
@@ -143,6 +143,8 @@
class EditorPage(widgets.PanelWithBoxSizer):
def __init__(self, parent, item, *args, **kwargs):
super(EditorPage, self).__init__(parent, *args, **kwargs)
+ self._defaultControl=None
+ self._fieldMap={}
self._item = item
def addHeaders(self, box):
@@ -154,6 +156,19 @@
for header in headers:
box.add(header)
+ def containsField(self,fieldname):
+ return fieldname in self._fieldMap.keys()
+
+ def setFocusForField(self, fieldname):
+ ''' if a field has an associated control, set focus on that control.
+ if not, set focus to the default control.
+ '''
+ if self.containsField(fieldname):
+ self._fieldMap[fieldname].SetFocus()
+ else:
+ self._defaultControl.SetFocus()
+
+
def ok(self):
pass
@@ -177,7 +192,29 @@
self.addPriorityEntry()
self.addColorEntry()
self.fit()
+ self._defaultControl=self._subjectEntry
+ self._fieldMap={} #FIXME: cz: remove when subject page is an editor
page
+ self._fieldMap['subject'] = self._subjectEntry
+ self._fieldMap['description']= self._descriptionEntry
+ self._fieldMap['priority'] = self._prioritySpinner
+ def containsField(self,fieldname):
+ #FIXME: cz: remove when subject page is an editor page
+ # print fieldname , " ",fieldname in self._fieldMap.keys(),' ',self
+ return fieldname in self._fieldMap.keys()
+
+ def setFocusForField(self, fieldname):
+ #FIXME: cz: remove when subject page is an editor page
+ ''' if a field has an associated control, set focus on that control.
+ if not, set focus to the default control.
+ '''
+ if self.containsField(fieldname):
+ self._fieldMap[fieldname].SetFocus()
+ else:
+ self._defaultControl.SetFocus()
+
+
+
def addSubjectEntry(self):
self._subjectEntry = widgets.SingleLineTextCtrl(self,
self._item.subject())
@@ -223,6 +260,7 @@
entry = DateEntry(datesBox, taskMethod(),
callback=self.onDateChanged)
setattr(self, '_%sEntry'%taskMethodName, entry)
+ self._fieldMap[taskMethodName]= entry
datesBox.add(entry)
if task.children():
recursiveEntry = DateEntry(datesBox,
@@ -236,7 +274,8 @@
reminderBox.add(_('Reminder'))
self._reminderDateTimeEntry = widgets.DateTimeCtrl(reminderBox,
task.reminder())
- # If the users has not set a reminder, make sure that the default
+ self._fieldMap['reminder']= self._reminderDateTimeEntry
+ # If the users has not set a reminder, make sure that the default
# date time in the reminder entry is a reasonable suggestion:
if self._reminderDateTimeEntry.GetValue() == date.DateTime.max:
self.suggestReminder()
@@ -249,6 +288,7 @@
panelSizer = wx.BoxSizer(wx.HORIZONTAL)
self._recurrenceEntry = wx.Choice(panel,
choices=[_('None'), _('Daily'), _('Weekly'), _('Monthly'),
_('Yearly')])
+ self._fieldMap['recurrence']= self._recurrenceEntry
self._recurrenceEntry.Bind(wx.EVT_CHOICE, self.onRecurrenceChanged)
panelSizer.Add(self._recurrenceEntry, flag=wx.ALIGN_CENTER_VERTICAL)
panelSizer.Add((3,-1))
@@ -296,7 +336,8 @@
box.fit()
self.add(box, proportion=0, flag=wx.EXPAND|wx.ALL, border=5)
self.fit()
-
+ self._defaultControl=self._reminderDateTimeEntry # need to confirm
this is the right box
+
def onRecurrenceChanged(self, event):
event.Skip()
recurrenceOn = event.String != _('None')
@@ -419,6 +460,21 @@
box.fit()
self.add(box, proportion=0, flag=wx.EXPAND|wx.ALL, border=5)
self.fit()
+ self._fieldMap['budget']=self._budgetEntry
+ #FIXME: cz: ? The calculated fields now actually set focus on budget
entry
+ # behavior can be chaned by adding a separate map, that can be checked
in containsField
+ # or changing the setFocusForField method to recognize NONE for field
+ # this behavior will be OK for now.
+ self._fieldMap['timeSpent']=self._budgetEntry
+ self._fieldMap['totalTimeSpent']=self._budgetEntry
+ self._fieldMap['totalBudget']=self._budgetEntry
+ self._fieldMap['timeLeft']=self._budgetEntry
+ self._fieldMap['budgetLeft']=self._budgetEntry
+ self._fieldMap['totalTimeLeft']=self._budgetEntry
+ self._fieldMap['hourlyFee']=self._hourlyFeeEntry
+ self._fieldMap['revenue']=self._hourlyFeeEntry
+ self._fieldMap['totalRevenue']=self._hourlyFeeEntry
+ self._defaultControl = self._budgetEntry
def ok(self):
self._item.setBudget(self._budgetEntry.get())
@@ -466,6 +522,8 @@
categoriesBox.fit()
self.add(categoriesBox)
self.fit()
+ self._fieldMap['categories']=self._treeCtrl
+ self._fieldMap['totalCategories']=self._treeCtrl # readOnlyFiled maps
to base
def getCategoryWithIndex(self, index):
children = self.__categories.rootItems()
@@ -520,6 +578,8 @@
self.add(notesBox, proportion=1, flag=wx.EXPAND|wx.ALL,
border=5)
self.TopLevelParent.Bind(wx.EVT_CLOSE, self.onClose)
+ self._fieldMap['note']=self.noteViewer # not sure of the fieldname
+ self._defaultControl=self.noteViewer # not sure of the fieldname
self.fit()
def onClose(self, event):
@@ -542,6 +602,7 @@
self._listCtrl.SetColumnWidth(0, 500)
attachmentBox.add(self._listCtrl, flag=wx.EXPAND|wx.ALL, proportion=1)
self._listData = {}
+ self._fieldMap['attachments']=self._listCtrl
boxSizer = wx.BoxSizer(wx.HORIZONTAL)
self._buttonBox = widgets.ButtonBox(attachmentBox,
@@ -695,6 +756,8 @@
behaviorBox.fit()
self.add(behaviorBox, border=5)
self.fit()
+ self._defaultControl=choice
+ self._fieldMap['behavior']=choice
def ok(self):
self._item.shouldMarkCompletedWhenAllChildrenCompleted = \
@@ -926,7 +989,8 @@
def __init__(self, parent, command, uiCommands, *args, **kwargs):
self._uiCommands = uiCommands
self._command = command
- super(EditorWithCommand, self).__init__(parent, command.name(), *args,
**kwargs)
+ bitmap=kwargs.pop('bitmap','edit') # hack due to bitmap being a
positional arg now
+ super(EditorWithCommand, self).__init__(parent, command.name(),
bitmap, *args, **kwargs)
self.setFocusOnFirstEntry()
def setFocusOnFirstEntry(self):
@@ -950,7 +1014,51 @@
self._taskList = taskList
self._categories = categories
super(TaskEditor, self).__init__(parent, command, uiCommands, bitmap,
*args, **kwargs)
+ self[0][0]._subjectEntry.SetSelection(-1, -1)
+ # This works on Linux Ubuntu 5.10, but fails silently on Windows XP:
+ self.setFocus(*args,**kwargs)
+ # This works on Windows XP, but fails silently on Linux Ubuntu 5.10:
+ wx.CallAfter(self.setFocus,*args,**kwargs)
+ # So we did just do it twice, guess it doesn't hurt
+ def setFocus(self, *args, **kwargs):
+ ''' select the correct page and correct control on a page
+ kwargs include:
+ Page -- index of page to select
+ Task -- index of task (in tabbed notebook)
+ Field -- field to highlight (overrides page)
+ '''
+ tsk=0
+ page=0
+ fieldname=''
+ #print args
+ #print kwargs
+ if kwargs.has_key('Task'):
+ tsk=kwargs['Task']
+ self.ChangeSelection(kwargs['Task']) # always go to the first
tab
+ if kwargs.has_key('Page'):
+ page=kwargs['Page']
+ selectCtrl= self[tsk][page]._defaultControl
+ if kwargs.has_key('Field'):
+ # lookup the what page the field is edite on.
+ fieldname=kwargs['Field']
+ page=self.getFieldPage(fieldname)
+ self[tsk].ChangeSelection(page) # go to the second tab, try by
name.
+ self[tsk].ChangeSelection(page) # go to the second tab, try by name.
+ self[tsk][page].setFocusForField(fieldname)
+
+ def getFieldPage(self,fieldname,task=0):
+ ''' return the page on which the field should be edited'''
+ page=0 #hard code the second page for sample
+ for p in range((self[task]).GetPageCount()):
+ if self[task][p].containsField(fieldname):
+ return p
+ return page
+
+ def addPages(self):
+ for task in self._command.items:
+ self.addPage(task)
+
def addPage(self, task):
page = TaskEditBook(self._interior, task, self._taskList,
self._uiCommands, self._settings, self._categories)
Index: taskcoachlib/gui/mainwindow.py
===================================================================
--- taskcoachlib/gui/mainwindow.py (revision 1174)
+++ taskcoachlib/gui/mainwindow.py (working copy)
@@ -20,8 +20,7 @@
from taskcoachlib import meta, patterns, widgets, command, help
from taskcoachlib.i18n import _
from taskcoachlib.domain import task, effort
-import viewer, viewercontainer, viewerfactory, toolbar, uicommand,\
- remindercontroller
+import viewer, viewercontainer, viewerfactory, toolbar,
uicommand,remindercontroller
Index: taskcoachlib/gui/uicommand.py
===================================================================
--- taskcoachlib/gui/uicommand.py (revision 1174)
+++ taskcoachlib/gui/uicommand.py (working copy)
@@ -1142,8 +1142,49 @@
menuText=taskList.editItemMenuText,
helpText=taskList.editItemHelpText, *args, **kwargs)
- def doCommand(self, event, show=True):
- editor = self.viewer.editTaskDialog(bitmap=self.bitmap)
+ def onCommandActivate(self, event, field=''):
+ '''
+ this is a menu command, so we need to check for enabled, but we also
want to
+ pass in an optional field.
+ '''
+ #FIXME: cz: I put this in early in the development cycle when adding
the 'field' parameter
+ # I am not sure if it is necessary
+ if self.enabled(event):
+ self.doCommand(event, True, field)
+
+
+
+ def doCommand(self, event, show=True, field=''):
+ '''
+ open the task editor
+
+ If the mouse has been clicked, check to see what column it is in.
+ open the appropriate page on the edit task dialog.
+ '''
+ #
+ columnName='subject'
+
+ if 'columnName' in dir(event):
+ columnName=event.columnName
+ #FIXME: cz: remove event.columnHeader everywhere, not used
+ try: #FIXME: cz: remove debug code
+ print 'doTaskEdit', columnName
+ except e: # AttributeError: # this is debug code. column name and
column header might not exist.
+ pass #just ignore exceptions for now.
+ # The following code will need to get executed someplace (for
treecontroller, but
+ # The event should carry the field to edit if appropriate
+ # pos = event.GetPosition()
+ # item, flags, col = self.tree.HitTest(pos)
+ # if item:
+ #
+ # Page should be the page that the column that is clicked on can be
+ # found on. This parameter should change to "FieldToEdit and the
editor should
+ # know where the field resides.
+ # can we pass the information in the event?
+ editor = self.viewer.editTaskDialog(bitmap=self.bitmap,
+ Field=columnName,
+ Task=0, # This is always
appropriate.
+ Page=1)
editor.Show(show)
Index: taskcoachlib/gui/viewer.py
===================================================================
--- taskcoachlib/gui/viewer.py (revision 1174)
+++ taskcoachlib/gui/viewer.py (working copy)
@@ -1064,7 +1064,7 @@
return dialog.editor.TaskEditor(wx.GetTopLevelParent(self),
command.EditTaskCommand(self.list, self.curselection()),
self.list, self.uiCommands, self.settings, self.categories,
- bitmap=kwargs['bitmap'])
+ *args,**kwargs)
editTaskDialog = editItemDialog
Index: taskcoachlib/widgets/dialog.py
===================================================================
--- taskcoachlib/widgets/dialog.py (revision 1174)
+++ taskcoachlib/widgets/dialog.py (working copy)
@@ -94,7 +94,25 @@
def addPages(self):
raise NotImplementedError
-
+ def SetSelection(self,tag_index):
+ ''' set the book's item by index. Note that index can be numeric or
name
+ This is the same signature that exists in the Notebook or Listbook
allowing polymorphism
+
+ SetSelection has been Deprecated in wxWidgets. Use Change Selection
instead
+ '''
+ #FIXME: cz: did I add these? I think my docstring and implementation
don't agree
+ self._interior.SetSelection(index)
+
+ def ChangeSelection(self,index):
+ ''' set the book's item by index. Note that index can be numeric or
name
+ This is the same signature that exists in the Notebook or Listbook
allowing polymorphism
+
+ SetSelection has been Deprecated in wxWidgets. Use Change Selection
instead
+ '''
+ #FIXME: cz: did I add these? I think my docstring and implementation
don't agree
+ self._interior.SetSelection(index)
+
+
class NotebookDialog(BookDialog):
def createInterior(self):
return notebook.Notebook(self._panel)
Index: taskcoachlib/widgets/treectrl.py
===================================================================
--- taskcoachlib/widgets/treectrl.py (revision 1174)
+++ taskcoachlib/widgets/treectrl.py (working copy)
@@ -387,3 +387,23 @@
item = self.GetNextVisible(item)
return count
+ def onItemActivated(self, event):
+ ''' override TreeMixin default behavior
+ we know that there is a column, so use it.
+ '''
+
+ pos=self.ScreenToClient(wx.GetMousePosition())
+ item, flags, col = self.HitTest(pos)
+ if item:
+ # only get the column name if the hittest returned an item
+ # otherwise the item was activated from the menu or by
doubleclicking
+ # on a portion of the treeview not containing a record.
+ #FIXME: cz Remove debug prints
+ print ('ItemActivated: column name %s, %s' %
(self._getColumn(col).name(),self._getColumn(col).header() ))
+ print ('Flags: %s, Col:%s, Text: %s' % (flags, col,
self.GetItemText(item, col)))
+ event.hitTestFlags=flags
+ # event.column=col
+ event.columnName=self._getColumn(col).name()
+ self.editCommand(event)
+ event.Skip(False)
+