Package Gnumed :: Package timelinelib :: Package wxgui :: Package components :: Module cattree |
[frames] | no frames]

# Source Code for Module Gnumed.timelinelib.wxgui.components.cattree

      1  # Copyright (C) 2009, 2010, 2011  Rickard Lindberg, Roger Lindberg
      2  #
      3  # This file is part of Timeline.
      4  #
      5  # Timeline is free software: you can redistribute it and/or modify
      6  # it under the terms of the GNU General Public License as published by
      7  # the Free Software Foundation, either version 3 of the License, or
      8  # (at your option) any later version.
      9  #
     10  # Timeline is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  # GNU General Public License for more details.
     14  #
     15  # You should have received a copy of the GNU General Public License
     16  # along with Timeline.  If not, see <http://www.gnu.org/licenses/>.
     17
     18
     19  import wx
     20  import wx.lib.agw.customtreectrl as customtreectrl
     21
     22  from timelinelib.db.exceptions import TimelineIOError
     23  from timelinelib.db.observer import STATE_CHANGE_CATEGORY
     24  from timelinelib.wxgui.dialogs.categoryeditor import WxCategoryEdtiorDialog
     25  from timelinelib.wxgui.utils import _ask_question
     26  from timelinelib.wxgui.utils import category_tree
     27  import timelinelib.wxgui.utils as gui_utils
     28
     29
     30  NO_CHECKBOX_TYPE = 0
     31  CHECKBOX_TYPE = 1
     32
     33
     34 -class CategoriesTree(customtreectrl.CustomTreeCtrl):
     35
     36 -    def __init__(self, parent, fn_handle_db_error):
     37          style = wx.BORDER_SUNKEN
     38          agwStyle = (customtreectrl.TR_HIDE_ROOT |
     39                      customtreectrl.TR_HAS_VARIABLE_ROW_HEIGHT |
     40                      customtreectrl.TR_LINES_AT_ROOT |
     41                      customtreectrl.TR_HAS_BUTTONS)
     42          if version_str_to_tuple(wx.__version__) < (2, 8, 11, 0):
     43              customtreectrl.CustomTreeCtrl.__init__(self, parent, style=style|agwStyle)
     44          else:
     45              customtreectrl.CustomTreeCtrl.__init__(self, parent, style=style, agwStyle=agwStyle)
     46          self._create_gui()
     47          self.controller = CategoriesTreeController(self, fn_handle_db_error)
     48
     49 -    def initialize_from_db(self, db):
     50          self.controller.initialize_from_db(db)
     51
     52 -    def initialize_from_timeline_view(self, view):
     53          self.controller.initialize_from_timeline_view(view)
     54
     55 -    def set_category_tree(self, tree, view_properties):
     56          self.DeleteAllItems()
     57          self.root = self.AddRoot("") # Hidden because of TR_HIDE_ROOT
     58          self._update_categories_from_tree(tree, self.root, view_properties)
     59          self.ExpandAll()
     60
     61 -    def get_selected_category(self):
     62          item = self.GetSelection()
     63          if item is None:
     64              return None
     65          category = self.GetPyData(item)
     66          return category
     67
     68 -    def destroy(self):
     69          self.controller.destroy()
     70
     71 -    def _create_gui(self):
     72          # Context menu
     73          self.mnu = wx.Menu()
     74          self.mnu_edit = wx.MenuItem(self.mnu, wx.ID_ANY, _("Edit..."))
     75          self.Bind(wx.EVT_MENU, self._mnu_edit_on_click, self.mnu_edit)
     76          self.mnu.AppendItem(self.mnu_edit)
     77          self.mnu_add = wx.MenuItem(self.mnu, wx.ID_ANY, _("Add..."))
     78          self.Bind(wx.EVT_MENU, self._mnu_add_on_click, self.mnu_add)
     79          self.mnu.AppendItem(self.mnu_add)
     80          self.mnu_delete = wx.MenuItem(self.mnu, wx.ID_ANY, _("Delete"))
     81          self.Bind(wx.EVT_MENU, self._mnu_delete_on_click, self.mnu_delete)
     82          self.mnu.AppendItem(self.mnu_delete)
     83          # Events on control
     84          self.Bind(customtreectrl.EVT_TREE_ITEM_CHECKED,
     85                    self._on_tree_item_checked, self)
     86          self.Bind(wx.EVT_RIGHT_DOWN, self._on_right_down)
     87          self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
     88
     94
     95 -    def _update_categories_from_tree(self, tree, root_item, view_properties):
     96          for (cat, subtree) in tree:
     97              legend_panel = wx.Panel(self, size=(10, 10))
     98              legend_panel.SetBackgroundColour(cat.color)
     99              if view_properties:
    100                  ct_type = CHECKBOX_TYPE
    101              else:
    102                  ct_type = NO_CHECKBOX_TYPE
    103              item = self.AppendItem(root_item, cat.name, ct_type=ct_type,
    104                                     wnd=legend_panel, data=cat)
    105              if view_properties:
    106                  visible = view_properties.category_visible(cat)
    107                  self.CheckItem2(item, visible)
    108              self._update_categories_from_tree(subtree, item, view_properties)
    109
    110 -    def _on_right_down(self, e):
    111          (item, flags) = self.HitTest(e.GetPosition())
    112          if item is not None:
    113              self.SelectItem(item, True)
    114          self._update_menu_enableness()
    115          self.PopupMenu(self.mnu)
    116
    117 -    def _on_key_down(self, e):
    118          if self.GetFirstVisibleItem() is None:
    119              return
    120          keycode = e.GetKeyCode()
    121          if keycode == wx.WXK_DELETE:
    122              self.controller.delete_selected_category()
    123          e.Skip()
    124
    125 -    def _mnu_add_on_click(self, e):
    126          self.controller.add_category()
    127
    128 -    def _mnu_edit_on_click(self, e):
    129          self.controller.edit_selected_category()
    130
    131 -    def _mnu_delete_on_click(self, e):
    132          self.controller.delete_selected_category()
    133
    134 -    def _on_tree_item_checked(self, e):
    135          tree_item = e.GetItem()
    136          cat = tree_item.GetData()
    137          tree_item_checked = tree_item.IsChecked()
    138          self.controller.check_category(cat, tree_item_checked)
    139
    140
    141 -class CategoriesTreeController(object):
    142
    143 -    def __init__(self, view, fn_handle_db_error):
    144          self.view = view
    145          self.db = None
    146          self.timeline_view = None
    147          self.fn_handle_db_error = fn_handle_db_error
    148
    149 -    def initialize_from_db(self, db):
    150          self._change_active_db(db)
    151          self.timeline_view = None
    152          self._update_category_tree()
    153
    154 -    def initialize_from_timeline_view(self, view):
    155          if view is None:
    156              new_timeline = None
    157          else:
    158              new_timeline = view.get_timeline()
    159          self._change_active_db(new_timeline)
    160          self.timeline_view = view
    161          self._update_category_tree()
    162
    163 -    def add_category(self):
    164          add_category(self.view, self.db, self.fn_handle_db_error)
    165
    166 -    def edit_selected_category(self):
    167          cat = self.view.get_selected_category()
    168          if cat:
    169              edit_category(self.view, self.db, cat, self.fn_handle_db_error)
    170
    171 -    def delete_selected_category(self):
    172          cat = self.view.get_selected_category()
    173          if cat:
    174              delete_category(self.view, self.db, cat, self.fn_handle_db_error)
    175
    176 -    def check_category(self, cat, checked):
    177          if self.timeline_view is None:
    178              raise Exception("Checking not allowed when there is no "
    179                              "timeline view.")
    180          self.timeline_view.get_view_properties().set_category_visible(cat, checked)
    181          self.timeline_view.redraw_timeline()
    182
    183 -    def destroy(self):
    184          if self.db:
    185              self.db.unregister(self._db_on_changed)
    186
    187 -    def _change_active_db(self, new_db):
    188          if self.db:
    189              self.db.unregister(self._db_on_changed)
    190          self.db = new_db
    191          if self.db:
    192              self.db.register(self._db_on_changed)
    193
    194 -    def _db_on_changed(self, state_change):
    195          if state_change == STATE_CHANGE_CATEGORY:
    196              self._update_category_tree()
    197
    198 -    def _update_category_tree(self):
    199          try:
    200              if self.db:
    201                  categories = self.db.get_categories()
    202              else:
    203                  categories = []
    204          except TimelineIOError, e:
    205              self.fn_handle_db_error(e)
    206          else:
    207              tree = category_tree(categories)
    208              if self.timeline_view:
    209                  vp = self.timeline_view.get_view_properties()
    210              else:
    211                  vp = None
    212              self.view.set_category_tree(tree, vp)
    213
    214
    215 -def edit_category(parent_ctrl, db, cat, fn_handle_db_error):
    216      def create_category_editor():
    217          return WxCategoryEdtiorDialog(parent_ctrl, _("Edit Category"), db, cat)
    218      gui_utils.show_modal(create_category_editor, fn_handle_db_error)
    219
    220
    221 -def add_category(parent_ctrl, db, fn_handle_db_error):
    222      def create_category_editor():
    223          return WxCategoryEdtiorDialog(parent_ctrl, _("Add Category"), db, None)
    224      gui_utils.show_modal(create_category_editor, fn_handle_db_error)
    225
    226
    227 -def delete_category(parent_ctrl, db, cat, fn_handle_db_error):
    228      delete_warning = _("Are you sure you want to "
    229                         "delete category '%s'?") % cat.name
    230      if cat.parent is None:
    231          update_warning = _("Events belonging to '%s' will no longer "
    232                             "belong to a category.") % cat.name
    233      else:
    234          update_warning = _("Events belonging to '%s' will now belong "
    235                             "to '%s'.") % (cat.name, cat.parent.name)
    236      question = "%s\n\n%s" % (delete_warning, update_warning)
    237      if _ask_question(question, parent_ctrl) == wx.YES:
    238          try:
    239              db.delete_category(cat)
    240          except TimelineIOError, e:
    241              fn_handle_db_error(e)
    242
    243
    244 -def version_str_to_tuple(version_str):
    245      """
    246      >>> version_str_to_tuple("0.4.44.3")
    247      (0, 4, 44, 3)
    248      """
    249      return tuple([int(x) for x in version_str.split(".")])
    250