From: Matthias Kramm Date: Thu, 27 May 2010 00:59:54 +0000 (-0700) Subject: added missing files X-Git-Tag: version-0-9-1~14 X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=commitdiff_plain;h=e37b83503aa09d36d7e32327d9bd1f6c42708890 added missing files --- diff --git a/wx/gui/options/viewer.py b/wx/gui/options/viewer.py index b0e69ac..e6693e6 100644 --- a/wx/gui/options/viewer.py +++ b/wx/gui/options/viewer.py @@ -30,6 +30,7 @@ from lib.wordwrap import wordwrap from gui.boldstatictext import BoldStaticText import viewers import gui.fields +import gui.plugin import viewers.raw import viewers.simple diff --git a/wx/lib/__init__.py b/wx/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wx/lib/app.py b/wx/lib/app.py new file mode 100644 index 0000000..072b79d --- /dev/null +++ b/wx/lib/app.py @@ -0,0 +1,508 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +# +# gpdf2swf.py +# graphical user interface for pdf2swf +# +# Part of the swftools package. +# +# Copyright (c) 2008,2009 Matthias Kramm +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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 */ + +from __future__ import division +import os +import wx +import time +import pickle + +from lib.wordwrap import wordwrap +from wx.lib.pubsub import Publisher + +from document import Document +from gui.dialogs import (ProgressDialog, OptionsDialog, AboutDialog, InfoDialog) +from gui.gmain import (PdfFrame, + ID_INVERT_SELECTION, ID_SELECT_ODD, + ID_ONE_PAGE_PER_FILE, + ID_SELECT_EVEN, ID_DOC_INFO, + ) + + +def GetDataDir(): + """ + Return the standard location on this platform for application data + """ + sp = wx.StandardPaths.Get() + return sp.GetUserDataDir() + +def GetConfig(): + if not os.path.exists(GetDataDir()): + os.makedirs(GetDataDir()) + + config = wx.FileConfig( + localFilename=os.path.join(GetDataDir(), "options")) + return config + + +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) + # 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.view.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) + + 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 + ) + 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() + + + 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"") + + self.__progress.Destroy() + self.__progress = None + + 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 = "%s - %s (%s)" % (name, filename, self.__doc.title) + else: + t = "%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'),], + 1 : [('bitmap', '0'), ('poly2bitmap', '1'), ('bitmapfonts', '0'),], + 2 : [('bitmap', '0'), ('poly2bitmap', '0'), ('bitmapfonts', '0'),], + } + 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 Message(self, message): + dlg = wx.MessageDialog(self.view, + message, + style=wx.OK, pos=wx.DefaultPosition) + dlg.ShowModal() + dlg.Destroy() + diff --git a/wx/lib/document.py b/wx/lib/document.py new file mode 100644 index 0000000..cb9b00d --- /dev/null +++ b/wx/lib/document.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +# +# gpdf2swf.py +# graphical user interface for pdf2swf +# +# Part of the swftools package. +# +# Copyright (c) 2008,2009 Matthias Kramm +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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 */ + +from __future__ import division +import os +import time +import thread +import gfx +import wx +from wx.lib.pubsub import Publisher +from subprocess import Popen, PIPE + +class _SaveSWFThread: + def __init__(self, pdffilename, filename, one_page_per_file, doc, pages, options): + #self.__doc = doc + self.__filename = filename + self.__pdffilename = pdffilename + self.__pages = pages or range(1, doc.pages+1) + self.__options = options + self.__one_page_per_file = one_page_per_file + + def Start(self): + self.__keep_running = self.__running = True + thread.start_new_thread(self.Run, ()) + #self.Run() + + def Stop(self): + self.__keep_running = False + + def IsRunning(self): + return self.__running + + def Run(self): + swf = gfx.SWF() + + try: + plugin = self.__options.viewers.init(swf, self.__filename) + except Exception, e: + wx.CallAfter(Publisher.sendMessage, "PLUGIN_ERROR") + self.__running = False + return + + if self.__one_page_per_file and not plugin.one_page_per_file: + wx.CallAfter(Publisher.sendMessage, + "PLUGIN_ONE_PAGE_PER_FILE_NOT_SUPPORTED", + {'plugin': plugin,}) + self.__running = False + return + + pages = len(self.__pages) + wx.CallAfter(Publisher.sendMessage, "SWF_BEGIN_SAVE", + {'pages': pages,}) + + time.sleep(0.05) + + self.setparameters(gfx) + self.__doc = gfx.open("pdf", self.__pdffilename) + + self.setparameters(swf) + + try: + plugin.before_render() + except Exception, e: + wx.CallAfter(Publisher.sendMessage, "PLUGIN_ERROR") + self.__running = False + return + + for pagenr in self.__pages: + page = self.__doc.getPage(pagenr) + swf.startpage(page.width, page.height) + page.render(swf) + swf.endpage() + wx.CallAfter(Publisher.sendMessage, "SWF_PAGE_SAVED", + {'pagenr': pagenr, + 'pages': pages,}) + time.sleep(0.05) + + if self.__one_page_per_file: + form = '.%%0%dd.swf' % len(str(len(self.__pages))) + filename = self.__filename.replace('.swf', form % pagenr) + swf.save(filename) + swf = gfx.SWF() + self.setparameters(swf) + + if not self.__keep_running: + break + else: + # This will not run if we break the for loop + if not self.__one_page_per_file: + try: + plugin.before_save(page) + except Exception, e: + wx.CallAfter(Publisher.sendMessage, "PLUGIN_ERROR") + self.__running = False + return + swf.save(self.__filename) + try: + plugin.after_save(page) + except Exception, e: + wx.CallAfter(Publisher.sendMessage, "PLUGIN_ERROR") + self.__running = False + return + + # No need. But to be sure that it's clean up + # as soon as possible + del swf + + wx.CallAfter(Publisher.sendMessage, "SWF_FILE_SAVED") + time.sleep(0.05) + + self.__running = False + + def setparameters(self, swf): + #print "driver", swf + for opt in self.__options.quality: + if type(opt.name) in (tuple, list): + for name, value in ( + # Example to better understand the list comprehension: + # opt.name = ['a', 'b', 'c'] + # opt.value = [1, 2, 3] + # zip them = [('a',1), ('b', 2), ('c', 3)] + # pair will be in this example ('a', 1) due to + # the if pair[1] condition + pair for pair in zip(opt.name, opt.value) #if pair[1] == 1 + ): + #print "1.swf.setparameter(%s, %s)" % (name, value) + swf.setparameter(str(name), str(value)) + else: + #print "2.swf.setparameter(%s, %s)" % (opt.name, str(opt.value)) + swf.setparameter(opt.name, str(opt.value)) + + #swf.setparameter('noclips', '1') + #swf.setparameter('reordertags', '1') + #swf.setparameter('animate', '1') + +PDF_INFO = [ + "title", "subject", "keywords", "author", + "creator", "producer", "creationdate", "moddate", + "linearized", "tagged", "encrypted", "oktoprint", + "oktocopy", "oktochange", "oktoaddnotes", "version", +] + +class Document(object): + def __init__(self): + self.__page = None + self.__zoom = 1 + self.__lastsavefile = "output.swf" + self.__pdffilename = None + self.__preview_parameters = [] + + def __getattr__(self, name): + if name in PDF_INFO: + return self.__pdf.getInfo(name) or "n/a" + raise AttributeError, name + + def filename(self): + return self.__pdffilename + filename = property(filename) + + def __get_lastsavefile(self): + return self.__lastsavefile + def __set_lastsavefile(self, lastsavefile): + self.__lastsavefile = lastsavefile + lastsavefile = property(__get_lastsavefile, __set_lastsavefile) + + def __SwapExtension(self, filename, newext): + basename, ext = os.path.splitext(filename) + return "%s.%s" % (basename, newext) + + def __Reload(self): + Publisher.sendMessage("PAGE_CHANGED", + {'page': self.__page, + 'width': int(self.__page.width * self.__zoom), + 'height': int(self.__page.height * self.__zoom)}) + + def __get_preview_parameters(self): + return self.__preview_parameters + def __set_preview_parameters(self, parameters): + self.__preview_parameters = parameters + preview_parameters = property(__get_preview_parameters, + __set_preview_parameters) + + def Load(self, filename): + self.__lastsavefile = self.__SwapExtension(filename, "swf") + self.__pdffilename = filename + + #print 'Load',self.__preview_parameters + for parameter, value in self.__preview_parameters: + gfx.setparameter(parameter, value) + + try: + self.__pdf = gfx.open("pdf", filename) + except: + Publisher.sendMessage("FILE_NOT_LOADED", {'filename': filename}) + else: + Publisher.sendMessage("FILE_LOADED", {'pages': self.__pdf.pages}) + + def ChangePage(self, pagenr=1, size=None): + self.__page = page = self.__pdf.getPage(pagenr) + self.__Reload() + + def Fit(self, size): + w = size[0] / self.__page.width + h = size[1] / self.__page.height + self.__zoom = min(w, h) + self.__Reload() + + def Zoom(self, zoom): + if zoom == 1: + self.__zoom = 1 + else: + self.__zoom += zoom + self.__Reload() + + def GetThumbnails(self): + for pagenr in range(1, self.__pdf.pages + 1): + page = self.__pdf.getPage(pagenr) + yield page + + def SaveSWF(self, filename, one_page_per_file, pages, options): + self.__lastsavefile = filename + t = _SaveSWFThread(self.__pdffilename, filename, one_page_per_file, self.__pdf, pages, options) + t.Start() + return t + + diff --git a/wx/lib/embeddedimage.py b/wx/lib/embeddedimage.py new file mode 100644 index 0000000..5b3cad4 --- /dev/null +++ b/wx/lib/embeddedimage.py @@ -0,0 +1,74 @@ +#---------------------------------------------------------------------- +# Name: wx.lib.embeddedimage +# Purpose: Defines a class used for embedding PNG images in Python +# code. The primary method of using this module is via +# the code generator in wx.tools.img2py. +# +# Author: Anthony Tuininga +# +# Created: 26-Nov-2007 +# RCS-ID: $Id: embeddedimage.py 59672 2009-03-20 20:59:42Z RD $ +# Copyright: (c) 2007 by Anthony Tuininga +# Licence: wxWindows license +#---------------------------------------------------------------------- + +import base64 +import cStringIO +import wx + +try: + b64decode = base64.b64decode +except AttributeError: + b64decode = base64.decodestring + + +class PyEmbeddedImage(object): + """ + PyEmbeddedImage is primarily intended to be used by code generated + by img2py as a means of embedding image data in a python module so + the image can be used at runtime without needing to access the + image from an image file. This makes distributing icons and such + that an application uses simpler since tools like py2exe will + automatically bundle modules that are imported, and the + application doesn't have to worry about how to locate the image + files on the user's filesystem. + + The class can also be used for image data that may be acquired + from some other source at runtime, such as over the network or + from a database. In this case pass False for isBase64 (unless the + data actually is base64 encoded.) Any image type that + wx.ImageFromStream can handle should be okay. + """ + + def __init__(self, data, isBase64=True): + self.data = data + self.isBase64 = isBase64 + + def GetBitmap(self): + return wx.BitmapFromImage(self.GetImage()) + + def GetData(self): + if self.isBase64: + data = b64decode(self.data) + return data + + def GetIcon(self): + icon = wx.EmptyIcon() + icon.CopyFromBitmap(self.GetBitmap()) + return icon + + def GetImage(self): + stream = cStringIO.StringIO(self.GetData()) + return wx.ImageFromStream(stream) + + # added for backwards compatibility + getBitmap = GetBitmap + getData = GetData + getIcon = GetIcon + getImage = GetImage + + # define properties, for convenience + Bitmap = property(GetBitmap) + Icon = property(GetIcon) + Image = property(GetImage) + diff --git a/wx/lib/images.py b/wx/lib/images.py new file mode 100644 index 0000000..7b34b74 --- /dev/null +++ b/wx/lib/images.py @@ -0,0 +1,107 @@ +#---------------------------------------------------------------------- +# This file was generated by /usr/bin/img2py +# +from embeddedimage import PyEmbeddedImage + +blank = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAAZiS0dE" + "AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9kHDAscKjCK/4UAAABo" + "SURBVHja7dABAcBAEAIgXf/Ofo8dRKDblqPa5stxAgQIECBAgAABAgQIECBAgAABAgQIECBA" + "gAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEPALTbLLAQ8OIAV9" + "8WNeKwAAAABJRU5ErkJggg==") +getblankData = blank.GetData +getblankImage = blank.GetImage +getblankBitmap = blank.GetBitmap +getblankIcon = blank.GetIcon + +#---------------------------------------------------------------------- +stop = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAAXNSR0IArs4c6QAAAAZiS0dE" + "AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9kHGAEINtjJMYEAAADV" + "SURBVBjTPc8xTgJBAEbh988sLFkDXEAvgB338AhauI3EUqOVVhR6gq0s9Do2WpDVipaOLCZL" + "LGZ+G+IJ3ve0KssBUo3UWAJANtgL7JcCqXZVNcxmKXVdBBMn06S2bdT3xOvh8D3P50nPTyF2" + "O3xyjG9vpI/PrM3mrHAI/PZ9PHp79Xi5VAZ+7u7t7TY6BAI2g/2ehDAgBXSwABTKmWIyTr44" + "D93Do0FQX6Kv76T1Omo1Gl25qhqdzlLqdtE5E6fTpLaN6vuFVmU5kFQTQmMdMjn/b/4BTeBh" + "NrAp1ecAAAAASUVORK5CYII=") +getstopData = stop.GetData +getstopImage = stop.GetImage +getstopBitmap = stop.GetBitmap +getstopIcon = stop.GetIcon + +#---------------------------------------------------------------------- +gpdf2swf = PyEmbeddedImage( + "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" + "fQAAAABJRU5ErkJggg==") +getgpdf2swfData = gpdf2swf.GetData +getgpdf2swfImage = gpdf2swf.GetImage +getgpdf2swfBitmap = gpdf2swf.GetBitmap +getgpdf2swfIcon = gpdf2swf.GetIcon + diff --git a/wx/lib/utils.py b/wx/lib/utils.py new file mode 100644 index 0000000..75e80ff --- /dev/null +++ b/wx/lib/utils.py @@ -0,0 +1,55 @@ +import wx + +def blank_bmp(w, h, color="white"): + bmp = wx.EmptyBitmap(max(w,1) , max(h,1)) + clear_bmp(bmp, color) + return bmp + +def clear_bmp(bmp, color): + dc = wx.MemoryDC() + dc.SelectObject(bmp) + dc.SetBackground(wx.Brush(color)) + dc.Clear() + + +# Taken and adapt from django.utils.encoding +class GPdf2SwfUnicodeDecodeError(UnicodeDecodeError): + def __init__(self, obj, *args): + self.obj = obj + UnicodeDecodeError.__init__(self, *args) + + def __str__(self): + original = UnicodeDecodeError.__str__(self) + return '%s. You passed in %r (%s)' % (original, self.obj, + type(self.obj)) + +def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'): + try: + if not isinstance(s, basestring,): + if hasattr(s, '__unicode__'): + s = unicode(s) + else: + try: + s = unicode(str(s), encoding, errors) + except UnicodeEncodeError: + if not isinstance(s, Exception): + raise + # If we get to here, the caller has passed in an Exception + # subclass populated with non-ASCII data without special + # handling to display as a string. We need to handle this + # without raising a further exception. We do an + # approximation to what the Exception's standard str() + # output should be. + s = ' '.join([force_unicode(arg, encoding, strings_only, + errors) for arg in s]) + elif not isinstance(s, unicode): + # Note: We use .decode() here, instead of unicode(s, encoding, + # errors), so that if s is a SafeString, it ends up being a + # SafeUnicode at the end. + s = s.decode(encoding, errors) + except UnicodeDecodeError, e: + raise GPdf2SwfUnicodeDecodeError(s, *e.args) + #raise UnicodeDecodeError(*e.args) + return s + + diff --git a/wx/lib/wordwrap.py b/wx/lib/wordwrap.py new file mode 100644 index 0000000..4b1a5f8 --- /dev/null +++ b/wx/lib/wordwrap.py @@ -0,0 +1,97 @@ +#---------------------------------------------------------------------- +# Name: wx.lib.wordwrap +# Purpose: Contains a function to aid in word-wrapping some text +# +# Author: Robin Dunn +# +# Created: 15-Oct-2006 +# RCS-ID: $Id: wordwrap.py 54718 2008-07-19 18:57:26Z RD $ +# Copyright: (c) 2006 by Total Control Software +# Licence: wxWindows license +#---------------------------------------------------------------------- + +def wordwrap(text, width, dc, breakLongWords=True, margin=0): + """ + Returns a copy of text with newline characters inserted where long + lines should be broken such that they will fit within the given + width, with the given margin left and right, on the given `wx.DC` + using its current font settings. By default words that are wider + than the margin-adjusted width will be broken at the nearest + character boundary, but this can be disabled by passing ``False`` + for the ``breakLongWords`` parameter. + """ + + wrapped_lines = [] + text = text.split('\n') + for line in text: + pte = dc.GetPartialTextExtents(line) + wid = ( width - (2*margin+1)*dc.GetTextExtent(' ')[0] + - max([0] + [pte[i]-pte[i-1] for i in range(1,len(pte))]) ) + idx = 0 + start = 0 + startIdx = 0 + spcIdx = -1 + while idx < len(pte): + # remember the last seen space + if line[idx] == ' ': + spcIdx = idx + + # have we reached the max width? + if pte[idx] - start > wid and (spcIdx != -1 or breakLongWords): + if spcIdx != -1: + idx = spcIdx + 1 + wrapped_lines.append(' '*margin + line[startIdx : idx] + ' '*margin) + start = pte[idx] + startIdx = idx + spcIdx = -1 + + idx += 1 + + wrapped_lines.append(' '*margin + line[startIdx : idx] + ' '*margin) + + return '\n'.join(wrapped_lines) + + + +if __name__ == '__main__': + import wx + class TestPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent) + + self.tc = wx.TextCtrl(self, -1, "", (20,20), (150,150), wx.TE_MULTILINE) + self.Bind(wx.EVT_TEXT, self.OnDoUpdate, self.tc) + self.Bind(wx.EVT_SIZE, self.OnSize) + + + def OnSize(self, evt): + wx.CallAfter(self.OnDoUpdate, None) + + + def OnDoUpdate(self, evt): + WIDTH = self.GetSize().width - 220 + HEIGHT = 200 + bmp = wx.EmptyBitmap(WIDTH, HEIGHT) + mdc = wx.MemoryDC(bmp) + mdc.SetBackground(wx.Brush("white")) + mdc.Clear() + mdc.SetPen(wx.Pen("black")) + mdc.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)) + mdc.DrawRectangle(0,0, WIDTH, HEIGHT) + + text = wordwrap(self.tc.GetValue(), WIDTH-2, mdc, False) + #print repr(text) + mdc.DrawLabel(text, (1,1, WIDTH-2, HEIGHT-2)) + + del mdc + dc = wx.ClientDC(self) + dc.DrawBitmap(bmp, 200, 20) + + + app = wx.App(False) + frm = wx.Frame(None, title="Test wordWrap") + pnl = TestPanel(frm) + frm.Show() + app.MainLoop() + +