class TagsSelector(wx.Panel): def __init__(self, parent): super(TagsSelector, self).__init__(parent) self.__tagsWidth = 350 self.__tagsHeight = 150 self.__tagBitmap = wx.Bitmap(os.path.join(getImagesDir(), "tag.png"), wx.BITMAP_TYPE_PNG) self.label_tags = wx.StaticText(self, -1, _(u"Tags (comma separated)")) self.tagsTextCtrl = wx.TextCtrl(self, -1, "") self.tagsTextCtrl.SetMinSize((250, -1)) self.__tagsCloud = TagsCloud(self) self.__tagsCloud.SetMinSize((self.__tagsWidth, self.__tagsHeight)) self.__tagsCloud.Bind(EVT_TAG_LEFT_CLICK, self.__onTagClick) self.tagsTextCtrl.Bind(wx.EVT_TEXT, handler=self.__onTagsChanged) self.__layout() @property def tags(self): tagsString = self.tagsTextCtrl.GetValue().strip() tags = parseTagsList(tagsString) return tags @tags.setter def tags(self, tags): tagsString = getTagsString(tags) self.tagsTextCtrl.SetValue(tagsString) def __layout(self): titleTextSizer = wx.FlexGridSizer(1, 2, 0, 0) titleTextSizer.AddGrowableCol(1) titleTextSizer.Add(self.label_tags, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4) titleTextSizer.Add(self.tagsTextCtrl, 0, wx.ALL | wx.EXPAND, 0) mainSizer = wx.FlexGridSizer(2, 1, 0, 0) mainSizer.Add(titleTextSizer, 0, wx.ALL | wx.EXPAND, 4) mainSizer.Add(self.__tagsCloud, 0, wx.ALL | wx.EXPAND, 4) mainSizer.AddGrowableCol(0) mainSizer.AddGrowableRow(1) self.SetSizer(mainSizer) self.Layout() def __onTagClick(self, event): self.__addTagText(event.text) def __addTagText(self, tagname): currentText = self.tagsTextCtrl.GetValue().strip() if len(currentText) == 0: newtext = tagname elif currentText[-1] == ",": newtext = currentText + " " + tagname else: newtext = currentText + ", " + tagname self.tagsTextCtrl.SetValue(newtext) self.tagsTextCtrl.SetFocus() self.tagsTextCtrl.SetSelection(len(newtext), len(newtext)) def setTagsList(self, tagsList): self.__tagsCloud.setTags(tagsList) def _sendTagsListChangedEvent(self): propagationLevel = 10 newevent = TagsListChangedEvent(tags=self.tags) newevent.ResumePropagation(propagationLevel) wx.PostEvent(self, newevent) def __onTagsChanged(self, event): self._sendTagsListChangedEvent()
class SearchPanel(BasePagePanel): def __init__(self, parent, application): BasePagePanel.__init__(self, parent, application) self._allTags = None # Текущий результат поиска (список страниц) self._currentResultPages = [] # Секция для хранения найденных результатов (кэш) self._resultsSection = u"SearchResults" self.sortStrategySection = u"Sort" self._resultOptionTemplate = u"page_%d" self._strategyList = [AnyTagSearchStrategy, AllTagsSearchStrategy] self._sortStrategies = getSortStrategies() self._searchText = wx.StaticText(self, label=_('Phrase for search:')) self.wordsTextCtrl = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER) self.tagsLabel = wx.StaticText(self, -1, _(u"Tags: ")) self.tagsList = TagsCloud(self) self.tagsList.SetMinSize((250, 150)) strategies = [_(u"Any tag"), _(u"All tags")] self.tagsStrategy = wx.RadioBox(self, -1, _(u"Tags"), choices=strategies, majorDimension=0, style=wx.RA_SPECIFY_ROWS) self.tagsStrategy.SetSelection(0) self.clearTagsBtn = wx.Button(self, -1, _(u"Clear all tags")) self.searchBtn = wx.Button(self, -1, _(u"Find")) self.resultWindow = wx.html2.WebView.New(self) self.sortLabel = wx.StaticText(self, -1, _(u"Sort by ")) self.sortStrategy = wx.ComboBox(self, style=wx.CB_DROPDOWN | wx.CB_READONLY) self.sortStrategy.SetMinSize((200, -1)) for sortStrategy in self._sortStrategies: self.sortStrategy.Append(sortStrategy.title) self.sortStrategy.SetSelection(0) self.__do_layout() self.clearTagsBtn.Bind(wx.EVT_BUTTON, handler=self.__onClear) self.wordsTextCtrl.Bind(wx.EVT_TEXT_ENTER, handler=self.__onFind) self.searchBtn.Bind(wx.EVT_BUTTON, handler=self.__onFind) self.sortStrategy.Bind(wx.EVT_COMBOBOX, handler=self.__onChangeSortStrategy) self.tagsList.Bind(EVT_TAG_LEFT_CLICK, handler=self.__onTagLeftClick) def __do_layout(self): mainSizer = wx.FlexGridSizer(cols=1) mainSizer.AddGrowableRow(3) mainSizer.AddGrowableCol(0) searchSizer = wx.FlexGridSizer(cols=2) searchSizer.AddGrowableCol(1) searchSizer.Add(self._searchText, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=4) searchSizer.Add(self.wordsTextCtrl, flag=wx.EXPAND | wx.ALL, border=4) mainSizer.Add(searchSizer, 1, wx.EXPAND, 0) rightSizer = wx.FlexGridSizer(cols=1) rightSizer.Add(self.tagsStrategy, 0, wx.EXPAND, 0) rightSizer.Add(self.clearTagsBtn, 0, wx.ALL | wx.EXPAND, 2) rightSizer.Add(self.searchBtn, 0, wx.ALL | wx.EXPAND, 2) rightSizer.AddGrowableRow(0) rightSizer.AddGrowableCol(0) tagsSizer = wx.FlexGridSizer(1, 3, 0, 0) tagsSizer.Add(self.tagsLabel, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4) tagsSizer.Add(self.tagsList, 0, wx.ALL | wx.EXPAND, 2) tagsSizer.Add(rightSizer, 1, wx.EXPAND, 0) tagsSizer.AddGrowableCol(1) mainSizer.Add(tagsSizer, 1, wx.EXPAND, 0) sortSizer = wx.BoxSizer(wx.HORIZONTAL) sortSizer.Add(self.sortLabel, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=2) sortSizer.Add(self.sortStrategy, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=2) mainSizer.Add(sortSizer, 1, wx.EXPAND, 0) mainSizer.Add(self.resultWindow, 1, wx.EXPAND | wx.ALL, border=2) self.SetSizer(mainSizer) self.Layout() def __onChangeSortStrategy(self, event): """ Изменение способа сортировки """ self.Save() if self.page is not None: self.__showResults(self._currentResultPages) def __getCurrentSortStrategy(self): """ Получить стратегию для выбранного типа сортировки """ return self._sortStrategies[self.sortStrategy.GetSelection()] def __onTagLeftClick(self, event): """ Обработчик события при клике по метке """ tag = event.text self.tagsList.mark(tag, not self.tagsList.isMarked(tag)) def Print(self): """ Печать страницы (на принтер) """ self.resultWindow.Print() def Clear(self): pass def __updatePageInfo(self): """ Обновить интерфейс, чтобы он соответствовал настройкам страницы """ assert self.page is not None self.__updateSearchPhrase() self.__updateTagsList() def __updateTagsList(self): """ Обновить список тегов """ assert self.page is not None # заполним список тегов list_items = TagsList(self._application.wikiroot) self.tagsList.setTags(list_items) tags = self.page.searchTags # Поставим галки, где нужно for tag in self._allTags: if tag in tags: self.tagsList.mark(tag) # Установим стратегию поиска по тегам strategyIndex = self._strategyList.index(self.page.strategy) self.tagsStrategy.SetSelection(strategyIndex) def __updateSearchPhrase(self): """ Записать искомую фразу из текущей страницы в интерфейс """ self.wordsTextCtrl.SetValue(self.page.phrase) def Save(self): """ Сохранить настройки страницы """ if (self.page is not None and not self.page.isRemoved and pageExists(self.page)): self.__saveSearchPhrase() self.__saveSearchTags() self.__saveSearchTagsStrategy() self.__saveSortStrategy() def __saveSearchPhrase(self): """ Сохранить искомую фразу в настройки страницы """ self.page.phrase = self.wordsTextCtrl.GetValue() def __saveSearchTags(self): """ Сохранить искомые теги в настройке страницы """ self.page.searchTags = self.__getSearchTags() def __saveSearchTagsStrategy(self): """ Сохранить стратегию поиска по тегам (все теги или любой тег) """ strategyIndex = self.tagsStrategy.GetSelection() self.page.strategy = self._strategyList[strategyIndex] def UpdateView(self, page): """ Обновить внешний вид страницы и отобразить найденные результаты """ self._allTags = TagsList(self.page.root) self.__updatePageInfo() self._currentResultPages = self.__loadResults() self.__showResults(self._currentResultPages) self.__loadSortStrategy() def __loadSortStrategy(self): assert self.page is not None sortOption = IntegerOption(self.page.params, self.page.paramsSection, self.sortStrategySection, 0) sort = sortOption.value if sort < 0 or sort >= len(self._sortStrategies): sort = 0 self.sortStrategy.SetSelection(sort) def __saveSortStrategy(self): assert self.page is not None sortOption = IntegerOption(self.page.params, self.page.paramsSection, self.sortStrategySection, 0) sortOption.value = self.sortStrategy.GetSelection() def __onFind(self, event): """ Обработчик события кнопки "Найти" """ assert self.page is not None self.page.updateDateTime() self.Save() phrase = self.__getSearchPhrase() tags = self.__getSearchTags() searcher = Searcher(phrase, tags, self.page.strategy) runner = LongProcessRunner(searcher.find, self._application.mainWindow, _(u"Search"), _(u"Search pages...")) self._currentResultPages = runner.run(self.page.root) self.__saveResults(self._currentResultPages) self.__showResults(self._currentResultPages) def __getSearchTags(self): """ Получить список искомых тегов """ tags = [] for tag in self._allTags: if self.tagsList.isMarked(tag): tags.append(tag) return tags def __getSearchPhrase(self): """ Получить искомую фразу """ return self.wordsTextCtrl.GetValue() def __showResults(self, resultPages): """ Показать результат """ sortStrategy = self.__getCurrentSortStrategy() resultPages_sorted = resultPages[:] resultPages_sorted.sort(key=sortStrategy.sort, reverse=sortStrategy.inverse) report = HtmlReport(resultPages_sorted, self.__getSearchPhrase(), self.__getSearchTags(), self._application) htmltext = report.generate() self.resultWindow.SetPage(htmltext, self.page.path) def __saveResults(self, resultPages): """ Сохранить найденные страницы в конфиг """ assert self.page is not None self.page.params.remove_section(self._resultsSection) for n in range(len(resultPages)): option = self._resultOptionTemplate % n self.page.params.set(self._resultsSection, option, resultPages[n].subpath) def __loadResults(self): """ Загрузить найденные страницы из конфига """ assert self.page is not None n = 0 resultPages = [] try: while True: option = self._resultOptionTemplate % n subpath = self.page.params.get(self._resultsSection, option) page = self.page.root[subpath] if page is not None: resultPages.append(page) n += 1 except BaseException: pass return resultPages def __onClear(self, event): """ Очистка выбранных тегов """ self.tagsList.clearMarks()