# # This file is part of Documancer (http://documancer.sf.net) # # Copyright (C) 2002-2005 Vaclav Slavik # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # $Id: MainFrame.py,v 1.46 2005/02/06 12:54:15 vaclavslavik Exp $ # import sys from wxPython.wx import * import HtmlBrowser from BooksManagerDialog import BooksManagerDialog import utils, book, indexer, server, cache # begin wxGlade: dependencies # end wxGlade # ------------------------------------------------------------------------- # IDs # ------------------------------------------------------------------------- ID_UPDATE_CACHE = wxNewId() ID_HOME = wxNewId() ID_BACK = wxNewId() ID_FORWARD = wxNewId() ID_STOP = wxNewId() ID_REFRESH = wxNewId() ID_NEXT_MATCH = wxNewId() ID_PREV_MATCH = wxNewId() ID_FULLSCREEN = wxNewId() ID_ABOUT = wxNewId() ID_MANAGE_BOOKS = wxNewId() ID_CONFIG_MOZILLA = wxNewId() ID_BOOK_PICKER = wxNewId() ID_SEARCH_TEXT = wxNewId() ID_SEARCH_BUTTON = wxNewId() ID_SEARCH_RESULTS = wxNewId() ID_BOOKMARKS = wxNewId() ID_ADD_BOOKMARK = wxNewId() ID_DEL_BOOKMARK = wxNewId() ID_CONTENTS = wxNewId() ID_FOCUS_SEARCH = wxNewId() ID_FOCUS_BOOKMARKS = wxNewId() ID_FOCUS_SEARCH_RESULTS = wxNewId() ID_FOCUS_BROWSER = wxNewId() # ------------------------------------------------------------------------- # Helpers # ------------------------------------------------------------------------- if sys.platform == 'win32': def LoadBitmap(name): # wx and WinXP have problems with alpha channel in toolbar bitmaps: img = wxImage(name) if img.HasAlpha(): img.ConvertAlphaToMask() return wxBitmapFromImage(img) else: def LoadBitmap(name): return wxBitmap(name, wxBITMAP_TYPE_ANY) # ------------------------------------------------------------------------- # BookNotebook # ------------------------------------------------------------------------- class BookNotebook(wxNotebook): """Notebook class that allows access to pages by their name.""" def __init__(self, parent): wxNotebook.__init__(self, parent, -1, style=0) self.pageOrder = [] self.pageWindows = {} self.pageLabels = {} self.pageShown = {} def _pageOrderShown(self): return [ p for p in self.pageOrder if self.pageShown[p] ] def AddNamedPage(self, id, window, label): self.pageOrder.append(id) self.pageWindows[id] = window self.pageLabels[id] = label self.pageShown[id] = True self.AddPage(window, label) def ShowNamedPage(self, id, show): if show == self.pageShown[id]: return if show: self.pageShown[id] = show pos = self._pageOrderShown().index(id) self.InsertPage(pos, self.pageWindows[id], self.pageLabels[id]) else: pos = self._pageOrderShown().index(id) self.RemovePage(pos) self.pageShown[id] = show def SetNamedSelection(self, id): try: self.SetSelection(self._pageOrderShown().index(id)) except ValueError: self.SetSelection(0) def GetNamedSelection(self): return self._pageOrderShown()[self.GetSelection()] # ------------------------------------------------------------------------- # MainFrame # ------------------------------------------------------------------------- class MainFrame(wxFrame): def __init__(self, *args, **kwds): # begin wxGlade: MainFrame.__init__ kwds["style"] = wxDEFAULT_FRAME_STYLE wxFrame.__init__(self, *args, **kwds) self.splitter = wxSplitterWindow(self, -1) self.window_1_pane_1 = wxPanel(self.splitter, -1) self.notebook = BookNotebook(self.window_1_pane_1) self.bookmarks_pane = wxPanel(self.notebook, -1) self.search_pane = wxPanel(self.notebook, -1) # Menu Bar self.main_frame_menubar = wxMenuBar() self.SetMenuBar(self.main_frame_menubar) self.file_menu = wxMenu() self.file_menu.Append(ID_UPDATE_CACHE, "&Update index", "", wxITEM_NORMAL) self.file_menu.AppendSeparator() self.file_menu.Append(wxID_EXIT, "&Exit\tAlt-X", "", wxITEM_NORMAL) self.main_frame_menubar.Append(self.file_menu, "&File") wxglade_tmp_menu = wxMenu() wxglade_tmp_menu.Append(ID_HOME, "&Home", "", wxITEM_NORMAL) wxglade_tmp_menu.Append(ID_BACK, "&Back\tAlt-Left", "", wxITEM_NORMAL) wxglade_tmp_menu.Append(ID_FORWARD, "&Forward\tAlt-Right", "", wxITEM_NORMAL) wxglade_tmp_menu.AppendSeparator() wxglade_tmp_menu.Append(ID_PREV_MATCH, "&Previous match\tCtrl-Left", "", wxITEM_NORMAL) wxglade_tmp_menu.Append(ID_NEXT_MATCH, "&Next match\tCtrl-Right", "", wxITEM_NORMAL) self.main_frame_menubar.Append(wxglade_tmp_menu, "&Go") self.settings_menu = wxMenu() self.settings_menu.Append(ID_MANAGE_BOOKS, "&Manage books...", "", wxITEM_NORMAL) self.settings_menu.AppendSeparator() self.settings_menu.Append(ID_CONFIG_MOZILLA, "Configure &Mozilla", "", wxITEM_NORMAL) self.main_frame_menubar.Append(self.settings_menu, "&Settings") wxglade_tmp_menu = wxMenu() wxglade_tmp_menu.Append(ID_ABOUT, "&About", "", wxITEM_NORMAL) self.main_frame_menubar.Append(wxglade_tmp_menu, "&Help") # Menu Bar end # Tool Bar self.main_frame_toolbar = wxToolBar(self, -1, style=wxTB_HORIZONTAL|wxTB_FLAT|wxTB_DOCKABLE) self.SetToolBar(self.main_frame_toolbar) self.main_frame_toolbar.AddSeparator() self.main_frame_toolbar.AddLabelTool(ID_MANAGE_BOOKS, "Manage books", LoadBitmap("data/properties.png"), wxNullBitmap, wxITEM_NORMAL, "Manage books", "") self.main_frame_toolbar.AddSeparator() self.main_frame_toolbar.AddLabelTool(ID_HOME, "Home", LoadBitmap("data/go_home.png"), wxNullBitmap, wxITEM_NORMAL, "Return to homepage", "") self.main_frame_toolbar.AddLabelTool(ID_BACK, "Go back", LoadBitmap("data/go_left.png"), wxNullBitmap, wxITEM_NORMAL, "Go to previous page", "") self.main_frame_toolbar.AddLabelTool(ID_FORWARD, "Go forward", LoadBitmap("data/go_right.png"), wxNullBitmap, wxITEM_NORMAL, "Go to next page", "") self.main_frame_toolbar.AddLabelTool(ID_STOP, "Stop", LoadBitmap("data/stop.png"), wxNullBitmap, wxITEM_NORMAL, "Stop loading the page", "") self.main_frame_toolbar.AddLabelTool(ID_REFRESH, "Refresh", LoadBitmap("data/refresh.png"), wxNullBitmap, wxITEM_NORMAL, "Reload the page", "") self.main_frame_toolbar.AddSeparator() self.main_frame_toolbar.AddLabelTool(ID_PREV_MATCH, "Previous match", LoadBitmap("data/prev_match.png"), wxNullBitmap, wxITEM_NORMAL, "Go to previous occurence of searched term", "") self.main_frame_toolbar.AddLabelTool(ID_NEXT_MATCH, "Next match", LoadBitmap("data/next_match.png"), wxNullBitmap, wxITEM_NORMAL, "Go to next occurence of searched term", "") self.main_frame_toolbar.AddSeparator() self.main_frame_toolbar.AddLabelTool(ID_FULLSCREEN, "Fullscreen", LoadBitmap("data/fullscreen.png"), wxNullBitmap, wxITEM_CHECK, "Maximalize Documancer window to entire screen", "") # Tool Bar end self.contents_pane = wxPanel(self.notebook, -1) self.label_1 = wxStaticText(self.search_pane, -1, "&Search:") self.search_text = wxTextCtrl(self.search_pane, ID_SEARCH_TEXT, "", style=wxTE_PROCESS_ENTER) self.search_button = wxBitmapButton(self.search_pane, ID_SEARCH_BUTTON, LoadBitmap("data/search.png")) self.search_warning = wxPanel(self.search_pane, -1) self.search_warning_label = wxStaticText(self.search_warning, -1, '') self.search_warning_label.SetForegroundColour('red') warnicon = wxArtProvider_GetBitmap(wxART_WARNING, wxART_OTHER, (22,22)) sizer = wxBoxSizer(wxHORIZONTAL) sizer.Add(wxStaticBitmap(self.search_warning, -1, warnicon), 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 8) sizer.Add(self.search_warning_label, 1, wxALIGN_CENTER_VERTICAL) self.search_warning.SetSizer(sizer) self.search_results = wxListCtrl(self.search_pane, ID_SEARCH_RESULTS, style=wxLC_REPORT|wxSUNKEN_BORDER) self.bookmarks = wxListBox(self.bookmarks_pane, ID_BOOKMARKS, choices=[""]) self.add_bmark = wxBitmapButton(self.bookmarks_pane, ID_ADD_BOOKMARK, LoadBitmap("data/add.png")) self.del_bmark = wxBitmapButton(self.bookmarks_pane, ID_DEL_BOOKMARK, LoadBitmap("data/remove.png")) self.browser = None self.RecreateBrowser() self.__set_properties() self.__do_layout() # end wxGlade self.contents = wxTreeCtrl(self.contents_pane, ID_CONTENTS, style=wxTR_DEFAULT_STYLE | wxSUNKEN_BORDER) sizer = wxBoxSizer(wxVERTICAL) sizer.Add(self.contents, 1, wxEXPAND | wxALL, 5) self.contents_pane.SetSizer(sizer) self.Show(1) # a bug in wxGTK 2.4.2: CreateStatusBar needs visible win self.statusbar = self.CreateStatusBar(2, wxST_SIZEGRIP) self.statusbar.SetStatusWidths([-1, 180]) self.splitter.SetMinimumPaneSize(60) self.book_combo = wxChoice(self.main_frame_toolbar, ID_BOOK_PICKER, size=(200,-1)) lastbook = utils.config().Read('/GuiState/last_book', '') if lastbook == '' or lastbook not in book.books: if len(book.books) > 0: self.currentBook = book.books[book.books.keys()[0]] else: self.currentBook = None else: self.currentBook = book.books[lastbook] self.UpdateBooksList() self.main_frame_toolbar.InsertControl(0, self.book_combo) self.main_frame_toolbar.Realize() self.UpdateAfterBookChange() EVT_MENU(self, ID_UPDATE_CACHE, self.OnUpdateIndex) EVT_MENU(self, wxID_EXIT, self.OnExit) EVT_MENU(self, ID_HOME, self.OnHome) EVT_MENU(self, ID_BACK, self.OnBack) EVT_MENU(self, ID_FORWARD, self.OnForward) EVT_MENU(self, ID_STOP, self.OnStop) EVT_MENU(self, ID_REFRESH, self.OnRefresh) EVT_MENU(self, ID_PREV_MATCH, self.OnPrevMatch) EVT_MENU(self, ID_NEXT_MATCH, self.OnNextMatch) EVT_MENU(self, ID_FULLSCREEN, self.OnFullScreen) EVT_MENU(self, ID_MANAGE_BOOKS, self.OnManageBooks) EVT_MENU(self, ID_CONFIG_MOZILLA, self.OnConfigMozilla) EVT_MENU(self, ID_ABOUT, self.OnAboutBox) EVT_CHOICE(self, ID_BOOK_PICKER, self.OnChangeBook) EVT_CLOSE(self, self.OnClose) EVT_BUTTON(self, ID_SEARCH_BUTTON, self.OnSearch) EVT_TEXT_ENTER(self, ID_SEARCH_TEXT, self.OnSearch) EVT_LIST_ITEM_SELECTED(self, ID_SEARCH_RESULTS, self.OnSearchResult) EVT_BUTTON(self, ID_ADD_BOOKMARK, self.OnAddBookmark) EVT_BUTTON(self, ID_DEL_BOOKMARK, self.OnDelBookmark) EVT_LISTBOX(self, ID_BOOKMARKS, self.OnOpenBookmark) EVT_TREE_ITEM_EXPANDING(self, ID_CONTENTS, self.OnContentsExpanding) EVT_TREE_SEL_CHANGED(self, ID_CONTENTS, self.OnContentsSelected) self.search_results.InsertColumn(0, "Score") self.search_results.InsertColumn(1, "Document") # Set some common shortcuts: self.SetAcceleratorTable(wxAcceleratorTable([ (wxACCEL_ALT, ord('B'), ID_FOCUS_BOOKMARKS), (wxACCEL_ALT, ord('L'), ID_FOCUS_SEARCH_RESULTS), (wxACCEL_ALT, ord('I'), ID_FOCUS_SEARCH), (wxACCEL_ALT, ord('O'), ID_FOCUS_BROWSER), (wxACCEL_ALT, WXK_LEFT, ID_BACK), (wxACCEL_ALT, WXK_RIGHT, ID_FORWARD) ])) EVT_MENU(self, ID_FOCUS_BOOKMARKS, self.OnChangeFocus) EVT_MENU(self, ID_FOCUS_SEARCH_RESULTS, self.OnChangeFocus) EVT_MENU(self, ID_FOCUS_SEARCH, self.OnChangeFocus) EVT_MENU(self, ID_FOCUS_BROWSER, self.OnChangeFocus) self.main_frame_menubar.Enable(ID_PREV_MATCH, 0) self.main_frame_menubar.Enable(ID_NEXT_MATCH, 0) self.main_frame_toolbar.EnableTool(ID_PREV_MATCH, 0) self.main_frame_toolbar.EnableTool(ID_NEXT_MATCH, 0) cache.notifications.add(self.OnCacheChange) self.OnHome(None) # load home page of last opened book def __set_properties(self): # begin wxGlade: MainFrame.__set_properties self.SetTitle("Documancer") _icon = wxEmptyIcon() _icon.CopyFromBitmap(wxBitmap("data/documancer.png", wxBITMAP_TYPE_ANY)) self.SetIcon(_icon) self.SetSize(wxDLG_SZE(self, (404, 288))) self.main_frame_toolbar.SetToolBitmapSize((24, 24)) self.main_frame_toolbar.Realize() self.search_button.SetSize((32, 32)) self.search_button.SetToolTipString("Search the book") self.bookmarks.SetSelection(0) self.add_bmark.SetSize((32, 32)) self.add_bmark.SetToolTipString("Bookmark currently displayed page") self.del_bmark.SetSize((32, 32)) self.del_bmark.SetToolTipString("Remove selected bookmark") self.del_bmark.SetFocus() self.splitter.SplitVertically(self.window_1_pane_1, self.browser, 226) # end wxGlade if sys.platform == 'win32': _icon = wxEmptyIcon() _icon.CopyFromBitmap(wxBitmap("data/documancer-16.png", wxBITMAP_TYPE_ANY)) self.SetIcon(_icon) def __do_layout(self): # begin wxGlade: MainFrame.__do_layout sizer_1 = wxBoxSizer(wxVERTICAL) sizer_2 = wxBoxSizer(wxVERTICAL) sizer_3 = wxBoxSizer(wxVERTICAL) sizer_4 = wxBoxSizer(wxHORIZONTAL) sizer_5 = wxBoxSizer(wxVERTICAL) sizer_6 = wxBoxSizer(wxHORIZONTAL) sizer_6.Add(self.label_1, 0, wxALL|wxALIGN_CENTER_VERTICAL, 4) sizer_6.Add(self.search_text, 1, wxALIGN_CENTER_VERTICAL, 0) sizer_6.Add(self.search_button, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 4) sizer_5.Add(sizer_6, 0, wxALL|wxEXPAND, 4) sizer_5.Add(self.search_warning, 0, wxALL|wxEXPAND, 4) sizer_5.Add(self.search_results, 1, wxEXPAND, 3) sizer_5.Show(self.search_warning, False) self.search_pane.SetAutoLayout(1) self.search_pane.SetSizer(sizer_5) sizer_5.Fit(self.search_pane) sizer_5.SetSizeHints(self.search_pane) sizer_3.Add(self.bookmarks, 1, wxALL|wxEXPAND, 3) sizer_4.Add(self.add_bmark, 0, 0, 0) sizer_4.Add(self.del_bmark, 0, wxLEFT, 3) sizer_3.Add(sizer_4, 0, wxALL|wxALIGN_RIGHT, 4) self.bookmarks_pane.SetAutoLayout(1) self.bookmarks_pane.SetSizer(sizer_3) sizer_3.Fit(self.bookmarks_pane) sizer_3.SetSizeHints(self.bookmarks_pane) self.notebook.AddNamedPage('content', self.contents_pane, 'Content') self.notebook.AddNamedPage('search', self.search_pane, 'Search') self.notebook.AddNamedPage('bookmarks', self.bookmarks_pane, 'Bookmarks') sizer_2.Add(wxNotebookSizer(self.notebook), 1, wxEXPAND, 0) self.window_1_pane_1.SetAutoLayout(1) self.window_1_pane_1.SetSizer(sizer_2) sizer_2.Fit(self.window_1_pane_1) sizer_2.SetSizeHints(self.window_1_pane_1) sizer_1.Add(self.splitter, 1, wxEXPAND, 0) self.SetAutoLayout(1) self.SetSizer(sizer_1) self.Layout() # end wxGlade self.SetSize((utils.config().ReadInt('/GuiState/MainFrame/width',500), utils.config().ReadInt('/GuiState/MainFrame/height',400))) self.Move((utils.config().ReadInt('/GuiState/MainFrame/pos_x',-1), utils.config().ReadInt('/GuiState/MainFrame/pos_y',-1))) self.splitter.SetSashPosition( utils.config().ReadInt('/GuiState/MainFrame/splitter_pos',200)) self.notebook.SetNamedSelection( utils.config().Read('/GuiState/MainFrame/selected_notebook_page','search')) def RecreateBrowser(self, name=None): old = self.browser self.browser = HtmlBrowser.create(self.splitter, -1, name) if old != None: self.splitter.ReplaceWindow(old, self.browser) old.Destroy() self.browser.OnPageChanged = self.OnPageChanged self.browser.OnStatusChanged = self.OnStatusChanged self.browser.OnTitleChanged = self.OnTitleChanged self.main_frame_menubar.Enable(ID_CONFIG_MOZILLA, self.browser.name == 'mozilla') def UpdateBooksList(self): self.book_combo.Clear() keys = book.books.keys() keys.sort() for b in keys: self.book_combo.Append(b) if self.currentBook != None: self.book_combo.SetStringSelection(self.currentBook.title) def UpdateAfterBookChange(self): if self.currentBook == None: return # reschedule updates to be done with this book first: cache.cache.setCurrentBook(self.currentBook) # Disables/enables search panel and update index page: self.UpdateSearchPane() # Add bookmarks: self.bookmarks.Clear() bmarks = self.currentBook.getBookmarks()[0] self.bookmarks.InsertItems(bmarks, 0) # Disable or add contents pane: cont = self.currentBook.getContents() self.contents.DeleteAllItems() self.notebook.ShowNamedPage('content', cont != None) if cont != None: root = self.contents.AddRoot(cont.name, data=wxTreeItemData(cont)) self.contents.SetItemHasChildren(root, cont.hasChildren()) self.contents.Expand(root) # If the book prefers another browser, change the browser: if self.currentBook.hasAttr('gui.pref_browser'): browser = self.currentBook.getAttr('gui.pref_browser') else: browser = None browser = HtmlBrowser.determineBrowser(browser) if browser != self.browser.name: self.RecreateBrowser(browser) def UpdateSearchPane(self): warning = None obj = indexer.getCacheObject(self.currentBook) isIndexed = obj.isActive() if isIndexed and not obj.exists(): isIndexed = False warning = 'Indexing, please wait...' self.search_text.Enable(isIndexed) self.search_results.Enable(isIndexed) self.search_button.Enable(isIndexed) if isIndexed: if obj.state != cache.STATE_UP_TO_DATE: warning = 'Outdated index, recreating...' # if the state is unknown, wait until it's determined: if obj.state == cache.STATE_UNKNOWN: warning = None # show or hide the warning: if warning != None: self.search_warning_label.SetLabel(warning) sizer = self.search_warning.GetContainingSizer() sizer.Show(self.search_warning, warning != None) sizer.Layout() def OnContentsExpanding(self, event): tree = self.contents id = event.GetItem() # did we already (try to) expand the node? if tree.GetChildrenCount(id, recursively=false) > 0: event.Skip() return # no, let's expand the node now: bcur=wxBusyCursor() node = tree.GetItemData(id).GetData() children = node.getChildren() if len(children) == 0: event.Veto() tree.SetItemHasChildren(id, 0) else: for c in children: cid = tree.AppendItem(id, c.name, data=wxTreeItemData(c)) tree.SetItemHasChildren(cid, c.hasChildren()) def OnContentsSelected(self, event): node = self.contents.GetItemData(event.GetItem()).GetData() if node.url != None: self.browser.LoadURL(self.currentBook.makeFullURL(node.url)) def OnExit(self, event): self.Close() def OnClose(self, event): """Saves main window size etc. on exit.""" cache.notifications.remove(self.OnCacheChange) # we can't send notifications to destroyed frame: utils.uiCallback.mainFrame = None self.browser.SavePrefs() cfg = utils.config() size = self.GetSize() cfg.WriteInt('/GuiState/MainFrame/width', size.x) cfg.WriteInt('/GuiState/MainFrame/height', size.y) pos = self.GetPosition() cfg.WriteInt('/GuiState/MainFrame/pos_x', pos.x) cfg.WriteInt('/GuiState/MainFrame/pos_y', pos.y) cfg.WriteInt('/GuiState/MainFrame/splitter_pos', self.splitter.GetSashPosition()) cfg.Write('/GuiState/MainFrame/selected_notebook_page', self.notebook.GetNamedSelection()) if self.currentBook != None: cfg.Write('/GuiState/last_book', self.currentBook.title) wxConfigBase_Set(None) utils.__configObject = None event.Skip() def OnManageBooks(self, event): mng = BooksManagerDialog(self, -1, '') if mng.ShowModal() == wxID_OK: self.currentBook = mng.CommitChanges(self.currentBook) self.UpdateBooksList() self.UpdateAfterBookChange() mng.Destroy() def OnConfigMozilla(self, event): self.browser.LoadURL('about:config') def OnFullScreen(self, event): self.ShowFullScreen(event.IsChecked(), wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION) def OnPageChanged(self, page): self.main_frame_toolbar.EnableTool(ID_BACK, self.browser.CanGoBack()) self.main_frame_toolbar.EnableTool(ID_FORWARD, self.browser.CanGoForward()) self._UpdateSearchMatchesNavigation(page) def OnTitleChanged(self, title): if title == '': self.SetTitle("Documancer") else: self.SetTitle("Documancer - %s" % title); def OnStatusChanged(self, text, isbusy): # FIXME - display busy status! self.statusbar.SetStatusText(text, 0) def OnHome(self, event): if self.currentBook != None: self.browser.LoadURL(self.currentBook.getHomeURL()) def OnBack(self, event): self.browser.GoBack() def OnForward(self, event): self.browser.GoForward() def OnStop(self, event): self.browser.Stop() def OnRefresh(self, event): self.browser.Reload() def OnChangeBook(self, event): self.currentBook = book.books[event.GetString()] self.UpdateAfterBookChange() self.OnHome(None) def OnSearch(self, event): bcur = wxBusyCursor() try: query = self.search_text.GetValue() self.search_results.DeleteAllItems() i = 0 self.searchResultURLs = [] for title, url, score in indexer.search(self.currentBook, query): self.search_results.InsertStringItem(i, score) self.search_results.SetStringItem(i, 1, title) self.searchResultURLs.append(url) i += 1 self.search_results.SetColumnWidth(0, wxLIST_AUTOSIZE) self.search_results.SetColumnWidth(1, wxLIST_AUTOSIZE) # automatically show first hit: if len(self.searchResultURLs) > 0: self.search_results.SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED) finally: bcur = None def OnSearchResult(self, event): bcur = wxBusyCursor() self.displayingSearchResult = 1 url = '%s#search_result_0' % self.searchResultURLs[event.GetIndex()] self.browser.LoadURL(url) def _UpdateSearchMatchesNavigation(self, url): hashpos = url.rfind('#search_result_') if hashpos == -1: self.main_frame_menubar.Enable(ID_PREV_MATCH, 0) self.main_frame_menubar.Enable(ID_NEXT_MATCH, 0) self.main_frame_toolbar.EnableTool(ID_PREV_MATCH, 0) self.main_frame_toolbar.EnableTool(ID_NEXT_MATCH, 0) return baseurl = url[:hashpos] pos = int(url[url.rfind('_')+1:]) try: count = server.queryHitsCounts[baseurl] except KeyError: count = 0 self.main_frame_menubar.Enable(ID_PREV_MATCH, pos != 0) self.main_frame_toolbar.EnableTool(ID_PREV_MATCH, pos != 0) self.main_frame_menubar.Enable(ID_NEXT_MATCH, pos < count-1) self.main_frame_toolbar.EnableTool(ID_NEXT_MATCH, pos < count-1) def _ChangeSearchMatch(self, delta): url = self.browser.GetPageURL() assert url.rfind('#search_result_') != -1 pos = url.rfind('_')+1 num = int(url[pos:]) newurl = '%s%i' % (url[:pos], num + delta) self.browser.LoadURL(newurl) def OnPrevMatch(self, event): self._ChangeSearchMatch(-1) def OnNextMatch(self, event): self._ChangeSearchMatch(1) def OnAddBookmark(self, event): title = wxGetTextFromUser("Please enter bookmark name:", "Add bookmark", self.browser.GetPageTitle(), parent=self) self.currentBook.addBookmark(title, self.browser.GetPageURL()) self.UpdateAfterBookChange() def OnDelBookmark(self, event): self.currentBook.delBookmark(self.bookmarks.GetStringSelection()) self.UpdateAfterBookChange() def OnOpenBookmark(self, event): bcur = wxBusyCursor() url = self.currentBook.getBookmarks()[1][event.GetString()] self.browser.LoadURL(url) def OnChangeFocus(self, event): id = event.GetId() if id == ID_FOCUS_SEARCH: self.notebook.SetNamedSelection('search') self.search_text.SetFocus() elif id == ID_FOCUS_SEARCH_RESULTS: self.notebook.SetNamedSelection('search') self.search_results.SetFocus() elif id == ID_FOCUS_BOOKMARKS: self.notebook.SetNamedSelection('bookmarks') self.bookmarks.SetFocus() elif id == ID_FOCUS_BROWSER: self.browser.SetFocus() def OnUpdateIndex(self, event): cache.get(self.currentBook).remakeAll() def OnAboutBox(self, event): from AboutBox import AboutBox dlg = AboutBox(self, -1, '') dlg.ShowModal() dlg.Destroy() def OnCacheChange(self, object): # called when some cache object changes if object.book == self.currentBook: wxCallAfter(self.UpdateSearchPane) # end of class MainFrame