def __init__(self, parent: wx.Window): super().__init__(parent) self._columns = [] # type: List[BaseColumn] self._pages = [] # type: List[outwiker.core.tree.WikiPage] self._defaultIcon = getBuiltinImagePath("page.png") self._imageList = ImageListCache(self._defaultIcon) self._propagationLevel = 15 self.SetBackgroundColour(wx.Colour(255, 255, 255)) self._sizer = wx.FlexGridSizer(cols=1) self._sizer.AddGrowableCol(0) self._sizer.AddGrowableRow(0) self._listCtrl = ULC.UltimateListCtrl( self, agwStyle=ULC.ULC_REPORT | ULC.ULC_SINGLE_SEL | ULC.ULC_VRULES | ULC.ULC_HRULES | ULC.ULC_SHOW_TOOLTIPS | ULC.ULC_NO_HIGHLIGHT ) self._listCtrl.Bind(ULC.EVT_LIST_ITEM_HYPERLINK, handler=self._onPageClick) self._listCtrl.Bind(ULC.EVT_LIST_COL_CLICK, handler=self._onColClick) self._listCtrl.SetHyperTextNewColour(wx.BLUE) self._listCtrl.SetHyperTextVisitedColour(wx.BLUE) self._listCtrl.AssignImageList(self._imageList.getImageList(), wx.IMAGE_LIST_SMALL) self._sizer.Add(self._listCtrl, flag=wx.EXPAND) self.SetSizer(self._sizer)
def test_empty(): app = wx.App() wx.Log.SetLogLevel(0) defaultImage = '../test/images/new.png' cache = ImageListCache(defaultImage) imageList = cache.getImageList() assert imageList.GetImageCount() == 1 assert cache.getDefaultImageId() == 0
def test_empty(): app = wx.App() wx.Log.SetLogLevel(0) defaultImage = 'testdata/images/new.png' cache = ImageListCache(defaultImage) imageList = cache.getImageList() assert imageList.GetImageCount() == 1 assert cache.getDefaultImageId() == 0
def test_error_invalid_file(): ''' Try add invalid file (not image) ''' app = wx.App() wx.Log.SetLogLevel(0) defaultImage = 'testdata/images/new.png' cache = ImageListCache(defaultImage) index = cache.add('testdata/images/invalid.png') imageList = cache.getImageList() assert index == 0 assert imageList.GetImageCount() == 1
def test_error_not_exists(): ''' Try add file which not exists ''' app = wx.App() wx.Log.SetLogLevel(0) defaultImage = 'testdata/images/new.png' cache = ImageListCache(defaultImage) index = cache.add('testdata/images/not_exists.png') imageList = cache.getImageList() assert index == 0 assert imageList.GetImageCount() == 1
def test_single(): ''' Add single image to empty ImageList ''' app = wx.App() wx.Log.SetLogLevel(0) defaultImage = 'testdata/images/new.png' cache = ImageListCache(defaultImage) index = cache.add('testdata/images/16x16.png') imageList = cache.getImageList() assert index == 1 assert imageList.GetImageCount() == 2
def test_error_not_exists(): ''' Try add file which not exists ''' app = wx.App() wx.Log.SetLogLevel(0) defaultImage = '../test/images/new.png' cache = ImageListCache(defaultImage) index = cache.add('../test/images/not_exists.png') imageList = cache.getImageList() assert index == 0 assert imageList.GetImageCount() == 1
def test_error_invalid_file(): ''' Try add invalid file (not image) ''' app = wx.App() wx.Log.SetLogLevel(0) defaultImage = '../test/images/new.png' cache = ImageListCache(defaultImage) index = cache.add('../test/images/invalid.png') imageList = cache.getImageList() assert index == 0 assert imageList.GetImageCount() == 1
def test_single(): ''' Add single image to empty ImageList ''' app = wx.App() wx.Log.SetLogLevel(0) defaultImage = '../test/images/new.png' cache = ImageListCache(defaultImage) index = cache.add('../test/images/16x16.png') imageList = cache.getImageList() assert index == 1 assert imageList.GetImageCount() == 2
def __init__(self, parent: wx.Window): super().__init__(parent) self._columns = [] # type: List[BaseColumn] self._pages = [] self._defaultIcon = os.path.join(getImagesDir(), "page.png") self._imageList = ImageListCache(self._defaultIcon) self._propagationLevel = 15 self.SetBackgroundColour(wx.Colour(255, 255, 255)) self._sizer = wx.FlexGridSizer(cols=1) self._sizer.AddGrowableCol(0) self._sizer.AddGrowableRow(0) self._listCtrl = ULC.UltimateListCtrl( self, agwStyle=ULC.ULC_REPORT | ULC.ULC_SINGLE_SEL | ULC.ULC_VRULES | ULC.ULC_HRULES | ULC.ULC_SHOW_TOOLTIPS | ULC.ULC_NO_HIGHLIGHT ) self._listCtrl.Bind(ULC.EVT_LIST_ITEM_HYPERLINK, handler=self._onPageClick) self._listCtrl.Bind(ULC.EVT_LIST_COL_CLICK, handler=self._onColClick) self._listCtrl.SetHyperTextNewColour(wx.BLUE) self._listCtrl.SetHyperTextVisitedColour(wx.BLUE) self._listCtrl.AssignImageList(self._imageList.getImageList(), wx.IMAGE_LIST_SMALL) self._sizer.Add(self._listCtrl, flag=wx.EXPAND) self.SetSizer(self._sizer)
def __init__(self, parent: wx.Window): treeStyle = (wx.TR_HAS_BUTTONS | wx.TR_EDIT_LABELS | wx.SUNKEN_BORDER) super().__init__(parent, style=treeStyle) self.defaultIcon = getBuiltinImagePath('page.png') self.iconHeight = ICON_HEIGHT # Картинки для дерева self._iconsCache = ImageListCache(self.defaultIcon) self.AssignImageList(self._iconsCache.getImageList()) # Кеш для страниц, чтобы было проще искать элемент дерева по странице # Словарь. Ключ - страница, значение - элемент дерева wx.TreeItemId self._pageCache = {} # Имя опции для сохранения развернутости страницы self.pageOptionExpand = 'Expand' self.Bind(wx.EVT_CLOSE, self.__onClose)
def test_duplicate(): ''' Add duplicate image to empty ImageList ''' app = wx.App() wx.Log.SetLogLevel(0) defaultImage = '../test/images/new.png' cache = ImageListCache(defaultImage) cache.add('../test/images/16x16.png') index = cache.add('../test/images/16x16.png') imageList = cache.getImageList() assert index == 1 assert imageList.GetImageCount() == 2
class PageList(wx.Panel): def __init__(self, parent: wx.Window): super().__init__(parent) self._columns = [] # type: List[BaseColumn] self._pages = [] # type: List[outwiker.core.tree.WikiPage] self._defaultIcon = getBuiltinImagePath("page.png") self._imageList = ImageListCache(self._defaultIcon) self._propagationLevel = 15 self.SetBackgroundColour(wx.Colour(255, 255, 255)) self._sizer = wx.FlexGridSizer(cols=1) self._sizer.AddGrowableCol(0) self._sizer.AddGrowableRow(0) self._listCtrl = ULC.UltimateListCtrl( self, agwStyle=ULC.ULC_REPORT | ULC.ULC_SINGLE_SEL | ULC.ULC_VRULES | ULC.ULC_HRULES | ULC.ULC_SHOW_TOOLTIPS | ULC.ULC_NO_HIGHLIGHT ) self._listCtrl.Bind(ULC.EVT_LIST_ITEM_HYPERLINK, handler=self._onPageClick) self._listCtrl.Bind(ULC.EVT_LIST_COL_CLICK, handler=self._onColClick) self._listCtrl.SetHyperTextNewColour(wx.BLUE) self._listCtrl.SetHyperTextVisitedColour(wx.BLUE) self._listCtrl.AssignImageList(self._imageList.getImageList(), wx.IMAGE_LIST_SMALL) self._sizer.Add(self._listCtrl, flag=wx.EXPAND) self.SetSizer(self._sizer) @property def listCtrl(self): return self._listCtrl @property def imageList(self): return self._imageList @property def _visibleColumns(self): return [col for col in self._columns if col.visible] def _onPageClick(self, event): item = event.GetItem() pageData = item.GetPyData() if pageData: page = pageData.page assert page is not None event = PageClickEvent(page=page) event.ResumePropagation(self._propagationLevel) wx.PostEvent(self, event) def _onColClick(self, event): self.sortByColumn(event.GetColumn()) def sortByColumn(self, col_index: int): for n, column in enumerate(self._visibleColumns): if n != col_index: column.set_sort_type(BaseColumn.SORT_NONE, self._listCtrl) column = self._visibleColumns[col_index] if column.sort_type == BaseColumn.SORT_NORMAL: column.set_sort_type(BaseColumn.SORT_INVERSE, self._listCtrl) else: column.set_sort_type(BaseColumn.SORT_NORMAL, self._listCtrl) if column.sort_type == BaseColumn.SORT_INVERSE: self._listCtrl.SortItems(column.sortFunctionInverse) else: self._listCtrl.SortItems(column.sortFunction) def clear(self): """ Удалить все элементы из списка """ self._listCtrl.ClearAll() def _createColumns(self): for n, column in enumerate(self._visibleColumns): column.insertColumn(self._listCtrl, n) def setPageList(self, pages): """ pages - список страниц, отображаемый в списке """ self._pages = pages self._updatePageList() def setColumns(self, columns: List[BaseColumn]): self._columns = columns self._updatePageList() def _updatePageList(self): self._listCtrl.Freeze() self.clear() self._createColumns() self._fillPageList() self._listCtrl.Thaw() def _fillPageList(self): for page in self._pages: items = [column.getCellContent(page) for column in self._visibleColumns] item_index = self._listCtrl.Append(items) for n, column in enumerate(self._visibleColumns): column.setCellProperties(self, item_index, n, page) data = PageData(page) self._listCtrl.SetItemPyData(item_index, data) def updateColumnsWidth(self): n = 0 for col in self._columns: if not col.visible: continue col.width = self._listCtrl.GetColumnWidth(n) n += 1 def getColumns(self) -> List[BaseColumn]: return self._columns
class PageList(wx.Panel): def __init__(self, parent: wx.Window): super().__init__(parent) self._columns = [] # type: List[BaseColumn] self._pages = [] self._defaultIcon = os.path.join(getImagesDir(), "page.png") self._imageList = ImageListCache(self._defaultIcon) self._propagationLevel = 15 self.SetBackgroundColour(wx.Colour(255, 255, 255)) self._sizer = wx.FlexGridSizer(cols=1) self._sizer.AddGrowableCol(0) self._sizer.AddGrowableRow(0) self._listCtrl = ULC.UltimateListCtrl( self, agwStyle=ULC.ULC_REPORT | ULC.ULC_SINGLE_SEL | ULC.ULC_VRULES | ULC.ULC_HRULES | ULC.ULC_SHOW_TOOLTIPS | ULC.ULC_NO_HIGHLIGHT ) self._listCtrl.Bind(ULC.EVT_LIST_ITEM_HYPERLINK, handler=self._onPageClick) self._listCtrl.Bind(ULC.EVT_LIST_COL_CLICK, handler=self._onColClick) self._listCtrl.SetHyperTextNewColour(wx.BLUE) self._listCtrl.SetHyperTextVisitedColour(wx.BLUE) self._listCtrl.AssignImageList(self._imageList.getImageList(), wx.IMAGE_LIST_SMALL) self._sizer.Add(self._listCtrl, flag=wx.EXPAND) self.SetSizer(self._sizer) @property def listCtrl(self): return self._listCtrl @property def imageList(self): return self._imageList @property def _visibleColumns(self): return [col for col in self._columns if col.visible] def _onPageClick(self, event): item = event.GetItem() pageData = item.GetPyData() if pageData: page = pageData.page assert page is not None event = PageClickEvent(page=page) event.ResumePropagation(self._propagationLevel) wx.PostEvent(self, event) def _onColClick(self, event): self.sortByColumn(event.GetColumn()) def sortByColumn(self, col_index: int): for n, column in enumerate(self._visibleColumns): if n != col_index: column.set_sort_type(BaseColumn.SORT_NONE, self._listCtrl) column = self._visibleColumns[col_index] if column.sort_type == BaseColumn.SORT_NORMAL: column.set_sort_type(BaseColumn.SORT_INVERSE, self._listCtrl) else: column.set_sort_type(BaseColumn.SORT_NORMAL, self._listCtrl) if column.sort_type == BaseColumn.SORT_INVERSE: self._listCtrl.SortItems(column.sortFunctionInverse) else: self._listCtrl.SortItems(column.sortFunction) def clear(self): """ Удалить все элементы из списка """ self._listCtrl.ClearAll() def _createColumns(self): for n, column in enumerate(self._visibleColumns): column.insertColumn(self._listCtrl, n) def setPageList(self, pages): """ pages - список страниц, отображаемый в списке """ self._pages = pages self._updatePageList() def setColumns(self, columns: List[BaseColumn]): self._columns = columns self._updatePageList() def _updatePageList(self): self._listCtrl.Freeze() self.clear() self._createColumns() self._fillPageList() self._listCtrl.Thaw() def _fillPageList(self): for page in self._pages: items = [column.getCellContent(page) for column in self._visibleColumns] item_index = self._listCtrl.Append(items) for n, column in enumerate(self._visibleColumns): column.setCellProperties(self, item_index, n, page) data = PageData(page) self._listCtrl.SetItemPyData(item_index, data) def updateColumnsWidth(self): n = 0 for col in self._columns: if not col.visible: continue col.width = self._listCtrl.GetColumnWidth(n) n += 1 def getColumns(self) -> List[BaseColumn]: return self._columns
class NotesTreeCtrl(wx.TreeCtrl): def __init__(self, parent: wx.Window): treeStyle = (wx.TR_HAS_BUTTONS | wx.TR_EDIT_LABELS | wx.SUNKEN_BORDER) super().__init__(parent, style=treeStyle) self.defaultIcon = getBuiltinImagePath('page.png') self.iconHeight = ICON_HEIGHT # Картинки для дерева self._iconsCache = ImageListCache(self.defaultIcon) self.AssignImageList(self._iconsCache.getImageList()) # Кеш для страниц, чтобы было проще искать элемент дерева по странице # Словарь. Ключ - страница, значение - элемент дерева wx.TreeItemId self._pageCache = {} # Имя опции для сохранения развернутости страницы self.pageOptionExpand = 'Expand' self.Bind(wx.EVT_CLOSE, self.__onClose) def __onClose(self, event): self._iconsCache.clear() def treeUpdate(self, rootPage): """ Обновить дерево """ self.DeleteAllItems() self._iconsCache.clear() # Ключ - страница, значение - экземпляр класса TreeItemId self._pageCache = {} if rootPage is not None: rootname = os.path.basename(rootPage.path) rootItem = self.AddRoot( rootname, data=rootPage, image=self._iconsCache.getDefaultImageId()) self._pageCache[rootPage] = rootItem self.__mountItem(rootItem, rootPage) self.appendChildren(rootPage) self.selectedPage = rootPage.selectedPage self.expand(rootPage) def appendChildren(self, parentPage): """ Добавить детей в дерево parentPage - родительская страница, куда добавляем дочерние страницы """ grandParentExpanded = self.__getItemExpandState(parentPage.parent) if grandParentExpanded: for child in parentPage.children: if child not in self._pageCache: self.insertChild(child) if self.__getPageExpandState(parentPage): self.expand(parentPage) def __mountItem(self, treeitem, page): """ Оформить элемент дерева в зависимости от настроек страницы (например, пометить только для чтения) """ if page.readonly: font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) font.SetStyle(wx.FONTSTYLE_ITALIC) self.SetItemFont(treeitem, font) def insertChild(self, childPage): """ Вставить одну дочерниюю страницу (childPage) в ветвь """ parentItem = self.getTreeItem(childPage.parent) assert parentItem is not None item = self.InsertItem(parentItem, childPage.order, childPage.display_title, data=childPage) self.SetItemImage(item, self.__loadIcon(childPage)) self._pageCache[childPage] = item self.__mountItem(item, childPage) self.appendChildren(childPage) return item def removePageItem(self, page): """ Удалить элемент, соответствующий странице и все его дочерние страницы """ for child in page.children: self.removePageItem(child) item = self.getTreeItem(page) if item is not None: del self._pageCache[page] self.Delete(item) def __loadIcon(self, page): """ Добавляет иконку страницы в ImageList и возвращает ее идентификатор. Если иконки нет, то возвращает идентификатор иконки по умолчанию """ icon = page.icon if not icon: return self._iconsCache.getDefaultImageId() icon = os.path.abspath(icon) imageId = self._iconsCache.add(icon) if imageId is None: imageId = self._iconsCache.getDefaultImageId() return imageId def updateIcon(self, page): if page not in self._pageCache: # Если нет этой страницы в дереве, то не важно, # изменилась иконка или нет return icon_id = self.__loadIcon(page) self.SetItemImage(self._pageCache[page], icon_id) def __getItemExpandState(self, page): """ Проверить, раскрыт ли элемент в дереве для страницы page """ if page is None: return True if page.parent is None: return True return self.IsExpanded(self._pageCache[page]) def __getPageExpandState(self, page): """ Проверить состояние "раскрытости" страницы """ if page is None: return True if page.parent is None: return True page_registry = page.root.registry.get_page_registry(page) expanded = page_registry.getbool(self.pageOptionExpand, default=False) return expanded def getTreeItem(self, page: 'outwiker.core.tree.WikiPage') -> Optional[wx.TreeItemId]: """ Получить элемент дерева по странице. Если для страницы не создан элемент дерева, возвращается None """ return self._pageCache.get(page) def expandToPage(self, page): """ Развернуть ветви до того уровня, чтобы появился элемент для page """ # Список родительских страниц, которые нужно добавить в дерево pages = [] currentPage = page.parent while currentPage is not None: pages.append(currentPage) currentPage = currentPage.parent pages.reverse() for page in pages: self.expand(page) def expand(self, page): item = self.getTreeItem(page) if item is not None: self.Expand(item) def createPage(self, newpage): if newpage.parent in self._pageCache: self.insertChild(newpage) assert newpage in self._pageCache item = self._pageCache[newpage] assert item.IsOk() self.expand(newpage) @property def selectedPage(self): page = None item = self.GetSelection() if item.IsOk(): page = self.GetItemData(item) # Проверка того, что выбрали не корневой элемент if page.parent is None: page = None return page @selectedPage.setter def selectedPage(self, newSelPage): if newSelPage is None: item = self.GetRootItem() else: self.expandToPage(newSelPage) item = self.getTreeItem(newSelPage) if item is not None: self.SelectItem(item)