class Pdf2Swf: def __init__(self): self.__doc = Document() self.__threads = {} self.__busy = None self.__progress = None self.__can_save = False self.__can_viewinfo = False self.view = PdfFrame() wx.GetApp().SetTopWindow(self.view) sys.excepthook = error.ErrorFrame(self.view) # Call Show after the current and pending event # handlers have been completed. Otherwise on MSW # we see the frame been draw and after that we saw # the menubar appear wx.CallAfter(self.Show) self.options = OptionsDialog(self.view) self.__ReadConfigurationFile() self.view.toolbar_preview_type.SetSelection(0) Publisher.subscribe(self.OnPageChanged, "PAGE_CHANGED") Publisher.subscribe(self.OnFileLoaded, "FILE_LOADED") Publisher.subscribe(self.OnFileNotLoaded, "FILE_NOT_LOADED") Publisher.subscribe(self.OnDiffSizes, "DIFF_SIZES") Publisher.subscribe(self.OnThumbnailAdded, "THUMBNAIL_ADDED") Publisher.subscribe(self.OnThumbnailDone, "THUMBNAIL_DONE") Publisher.subscribe(self.OnProgressBegin, "SWF_BEGIN_SAVE") Publisher.subscribe(self.OnProgressUpdate, "SWF_PAGE_SAVED") Publisher.subscribe(self.OnProgressDone, "SWF_FILE_SAVED") Publisher.subscribe(self.OnCombineError, "SWF_COMBINE_ERROR") Publisher.subscribe(self.OnFileDroped, "FILE_DROPED") Publisher.subscribe(self.OnFilesDroped, "FILES_DROPED") Publisher.subscribe(self.OnPluginOnePagePerFileNotSupported, "PLUGIN_ONE_PAGE_PER_FILE_NOT_SUPPORTED") Publisher.subscribe(self.OnPluginError, "PLUGIN_ERROR") self.view.Bind(wx.EVT_MENU, self.OnMenuOpen, id=wx.ID_OPEN) self.view.Bind(wx.EVT_MENU, self.OnMenuSave, id=wx.ID_SAVE) self.view.Bind(wx.EVT_MENU, self.OnMenuSaveSelected, id=wx.ID_SAVEAS) self.view.Bind(wx.EVT_MENU, self.OnMenuExit, id=wx.ID_EXIT) self.view.Bind(wx.EVT_MENU_RANGE, self.OnFileHistory, id=wx.ID_FILE1, id2=wx.ID_FILE9) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_SAVE) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_SAVEAS) self.view.Bind(wx.EVT_MENU, self.OnMenuSelectAll, id=wx.ID_SELECTALL) self.view.Bind(wx.EVT_MENU, self.OnMenuInvertSelection, id=ID_INVERT_SELECTION) self.view.Bind(wx.EVT_MENU, self.OnMenuSelectOdd, id=ID_SELECT_ODD) self.view.Bind(wx.EVT_MENU, self.OnMenuSelectEven, id=ID_SELECT_EVEN) self.view.Bind(wx.EVT_MENU, self.OnMenuOptions, id=wx.ID_PREFERENCES) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_SELECTALL) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_INVERT_SELECTION) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_SELECT_ODD) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_SELECT_EVEN) self.view.Bind(wx.EVT_MENU, self.OnAbout, id=wx.ID_ABOUT) self.view.Bind(wx.EVT_MENU, self.OnZoom, id=wx.ID_ZOOM_IN) self.view.Bind(wx.EVT_MENU, self.OnZoom, id=wx.ID_ZOOM_OUT) self.view.Bind(wx.EVT_MENU, self.OnZoom, id=wx.ID_ZOOM_100) self.view.Bind(wx.EVT_MENU, self.OnFit, id=wx.ID_ZOOM_FIT) self.view.Bind(wx.EVT_MENU, self.OnShowDocInfo, id=ID_DOC_INFO) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_ZOOM_IN) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_ZOOM_OUT) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_ZOOM_100) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=wx.ID_ZOOM_FIT) self.view.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUIInfo, id=ID_DOC_INFO) self.view.page_list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectItem) self.view.Bind(wx.EVT_CLOSE, self.OnMenuExit) self.view.toolbar_preview_type.Bind(wx.EVT_CHOICE, self.OnPreviewType) # statusbar cancel thumbanails generation button self.view.statusbar.btn_cancel.Bind(wx.EVT_BUTTON, self.OnThumbnailCancel) # Don't know where the problem is (python/xpython or wxwidgets/wxpython) # but I found that this hack was necessary to avoid the app enter in a # idle state. We must, for example, move the mouse inside the app # for threads continue their job. # There is no need for this when freezing with other utils, like # py2exe, pyinstaller, cxfreeze if "wxMSW" in wx.PlatformInfo: self.timer = wx.Timer(self.view) self.view.Bind(wx.EVT_TIMER, lambda evt: None) self.timer.Start(50) def OnFilesDroped(self, evt): dlg = wx.MessageDialog(self.view, u"You must drop only one file.", u"Notice", style=wx.OK, pos=wx.DefaultPosition) dlg.ShowModal() dlg.Destroy() def OnFileDroped(self, message): self.__Load(message.data["filename"]) def OnPluginOnePagePerFileNotSupported(self, message): self.Message(u"Selected viewer does not support " u"one page per file. ") def OnPluginError(self, message): self.Message(u"Error applying selected viewer") def OnFileHistory(self, evt): # get the file based on the menu ID fileNum = evt.GetId() - wx.ID_FILE1 filename = self.view.filehistory.GetHistoryFile(fileNum) self.__Load(filename) def OnProgressBegin(self, message): pages = message.data["pages"] style = (wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME | wx.PD_CAN_ABORT | wx.PD_AUTO_HIDE) if self.__progress: self.__progress.Destroy() self.__progress = ProgressDialog(u"Saving...", u"Start saving SWF pages", maximum=pages, parent=self.view, style=style) self.__progress.Show() self.view.SetStatusText(u"Saving document...") def OnProgressUpdate(self, message): pagenr = message.data["pagenr"] pages = message.data["pages"] keep_running = self.__progress.Update( pagenr, u"Saving SWF page %d of %d" % (pagenr, pages)) if not keep_running and self.__threads.has_key("progress"): self.view.SetStatusText(u"Cancelling...") self.__threads.pop("progress").Stop() self.__progress.Hide() def OnProgressDone(self, message): if self.__threads.has_key("progress"): # it goes all the way? self.__threads.pop("progress") self.view.SetStatusText(u"SWF document saved successfully.") else: self.view.SetStatusText(u"") def OnCombineError(self, message): from wx.lib.dialogs import ScrolledMessageDialog ScrolledMessageDialog(self.view, message.data, u"Notice").ShowModal() def OnThumbnailAdded(self, message): self.view.statusbar.SetGaugeValue(message.data['pagenr']) tot = self.view.page_list.GetItemCount() self.view.SetStatusText( u"Generating thumbnails %s/%d" % (message.data['pagenr'], tot), 0) def OnThumbnailDone(self, message): self.view.statusbar.SetGaugeValue(0) self.view.SetStatusText(u"", 0) if self.__threads.has_key("thumbnails"): self.__threads.pop("thumbnails") self.view.SendSizeEvent() def OnThumbnailCancel(self, event): if self.__threads.has_key("thumbnails"): self.__threads["thumbnails"].Stop() def OnSelectItem(self, event): self.__doc.ChangePage(event.GetIndex() + 1) def OnPreviewType(self, event): filename = self.__doc.filename if filename: self.__Load(filename) def OnPageChanged(self, message): # ignore if we have more than one item selected if self.view.page_list.GetSelectedItemCount() > 1: return self.view.page_preview.DisplayPage(message.data) def SetTitle(self): name = wx.GetApp().GetAppName() filename = os.path.basename(self.__doc.filename) if self.__doc.title != "n/a": t = u"%s - %s (%s)" % (name, filename, self.__doc.title) else: t = u"%s - %s" % (name, filename) self.view.SetTitle(t) def OnFileLoaded(self, message): if self.__progress: self.__progress.Destroy() self.__progress = None self.__can_viewinfo = True del self.__busy self.SetTitle() if self.__doc.oktocopy == 'no': self.__can_save = False self.view.page_list.DisplayEmptyThumbnails(0) self.view.page_preview.Clear() self.view.SetStatusText(u"") self.Message(u"This PDF disallows copying, cannot be converted.") return #if not self.__doc.oktoprint: self.view.SetStatusText(u"Document loaded successfully.") self.view.page_list.DisplayEmptyThumbnails(message.data["pages"]) thumbs = self.__doc.GetThumbnails() t = self.view.page_list.DisplayThumbnails(thumbs) self.__threads["thumbnails"] = t self.view.statusbar.SetGaugeRange(message.data["pages"]) #del self.__busy def OnFileNotLoaded(self, message): self.__can_save = False self.__can_viewinfo = False del self.__busy self.view.SetStatusText(u"") self.Message(u"Could not open file %s" % message.data['filename']) def OnDiffSizes(self, message): # just let the user know- for now, we can't handle this properly self.Message(u"In this PDF, width or height are not the same for " u"each page. This might cause problems if you export " u"pages of different dimensions into the same SWF file.") def OnMenuOpen(self, event): dlg = wx.FileDialog( self.view, u"Choose PDF File:", style=wx.OPEN | wx.CHANGE_DIR, wildcard=u"PDF files (*.pdf)|*.pdf|all files (*.*)|*.*") if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetPath() self.__Load(filename) def OnMenuSave(self, event, pages=None): defaultFile = self.__doc.lastsavefile if "wxMSW" in wx.PlatformInfo: allFiles = "*.*" else: allFiles = "*" self.view.SetStatusText(u"") dlg = wx.FileDialog(self.view, u"Choose Save Filename:", style=wx.SAVE | wx.OVERWRITE_PROMPT, defaultFile=os.path.basename(defaultFile), wildcard=u"SWF files (*.swf)|*.swf" "|all files (%s)|%s" % (allFiles, allFiles)) if dlg.ShowModal() == wx.ID_OK: menubar = self.view.GetMenuBar() one_file_per_page = menubar.IsChecked(ID_ONE_PAGE_PER_FILE) self.__threads["progress"] = self.__doc.SaveSWF( dlg.GetPath(), one_file_per_page, pages, self.options) def OnUpdateUI(self, event): menubar = self.view.GetMenuBar() menubar.Enable(event.GetId(), self.__can_save) self.view.GetToolBar().EnableTool(event.GetId(), self.__can_save) def OnUpdateUIInfo(self, event): menubar = self.view.GetMenuBar() menubar.Enable(event.GetId(), self.__can_viewinfo) self.view.GetToolBar().EnableTool(event.GetId(), self.__can_viewinfo) def OnMenuSaveSelected(self, event): pages = [] page = self.view.page_list.GetFirstSelected() pages.append(page + 1) while True: page = self.view.page_list.GetNextSelected(page) if page == -1: break pages.append(page + 1) self.OnMenuSave(event, pages) def OnMenuExit(self, event): self.view.SetStatusText(u"Cleaning up...") # Stop any running thread self.__StopThreads() config = GetConfig() self.view.filehistory.Save(config) config.Flush() # A little extra cleanup is required for the FileHistory control del self.view.filehistory # Save quality options dirpath = GetDataDir() data = self.options.quality_panel.pickle() try: f = file(os.path.join(dirpath, 'quality.pkl'), 'wb') pickle.dump(data, f) f.close() except Exception: pass # Save viewer options try: f = file(os.path.join(dirpath, 'viewers.pkl'), 'wb') data = self.options.viewers_panel.pickle() pickle.dump(data, f) f.close() except Exception: pass self.view.Destroy() def OnMenuSelectAll(self, event): for i in range(0, self.view.page_list.GetItemCount()): self.view.page_list.Select(i, True) def OnMenuInvertSelection(self, event): for i in range(0, self.view.page_list.GetItemCount()): self.view.page_list.Select(i, not self.view.page_list.IsSelected(i)) def OnMenuSelectOdd(self, event): for i in range(0, self.view.page_list.GetItemCount()): self.view.page_list.Select(i, not bool(i % 2)) def OnMenuSelectEven(self, event): for i in range(0, self.view.page_list.GetItemCount()): self.view.page_list.Select(i, bool(i % 2)) def OnMenuOptions(self, event): self.options.ShowModal() def OnFit(self, event): self.__doc.Fit(self.view.page_preview.GetClientSize()) def OnZoom(self, event): zoom = { wx.ID_ZOOM_IN: .1, wx.ID_ZOOM_OUT: -.1, wx.ID_ZOOM_100: 1, } self.__doc.Zoom(zoom[event.GetId()]) def OnShowDocInfo(self, event): info = InfoDialog(self.view) info.info.display(self.__doc) info.Show() def OnAbout(self, evt): AboutDialog(self.view) def __Load(self, filename): self.__can_save = True self.__StopThreads() self.view.SetStatusText(u"Loading document...") self.__busy = wx.BusyInfo(u"One moment please, " u"opening pdf document...") self.view.filehistory.AddFileToHistory(filename) try: # I dont care if this, for some reason, # give some error. I just swallow it os.chdir(os.path.dirname(filename)) except: pass # Need to delay the file load a little bit # for the BusyInfo get a change to repaint itself #wx.FutureCall(150, self.__doc.Load, filename) sel = self.view.toolbar_preview_type.GetSelection() #print sel PREV_TYPE = { 0: [('bitmap', '1'), ('poly2bitmap', '0'), ('bitmapfonts', '1'), ('textonly', '0')], 1: [('bitmap', '0'), ('poly2bitmap', '1'), ('bitmapfonts', '0'), ('textonly', '0')], 2: [('bitmap', '0'), ('poly2bitmap', '0'), ('bitmapfonts', '0'), ('textonly', '0')], 3: [('bitmap', '0'), ('poly2bitmap', '0'), ('bitmapfonts', '0'), ('textonly', '1')], } self.__doc.preview_parameters = PREV_TYPE[sel] wx.CallAfter(self.__doc.Load, filename) def __StopThreads(self): for n, t in self.__threads.items(): t.Stop() running = True while running: running = False for n, t in self.__threads.items(): running = running + t.IsRunning() time.sleep(0.1) def __ReadConfigurationFile(self): config = GetConfig() self.view.filehistory.Load(config) dirpath = GetDataDir() try: f = file(os.path.join(dirpath, 'quality.pkl'), 'rb') #try: if 1: data = pickle.load(f) self.options.quality_panel.unpickle(data) #except: # self.Message( # u"Error loading quality settings. " # u"They will be reset to defaults. ") f.close() except Exception: pass try: f = file(os.path.join(dirpath, 'viewers.pkl'), 'rb') #try: if 1: data = pickle.load(f) self.options.viewers_panel.unpickle(data) #except: # self.Message( # u"Error loading viewers settings. " # u"They will be reset to defaults. ") f.close() except Exception: pass #d = pickle.load(f) def Show(self): self.view.Show() if len(sys.argv) == 2: self.__Load(utils.force_unicode(sys.argv[1])) def Message(self, message): dlg = wx.MessageDialog(self.view, message, style=wx.OK, pos=wx.DefaultPosition) dlg.ShowModal() dlg.Destroy()