def __init__(self, parent, id, config, details): self.config = config config.interimProgress = self.Report self.InitLocale(details) wx.Frame.__init__(self, parent, id, "Evernote Palm importer") # IDs used for controls we'll interact with more than once self.ID_FILEBROWSE = wx.NewId() self.ID_ENCODING = wx.NewId() self.ID_LOCALE = wx.NewId() self.ID_STATUS = wx.NewId() self.ID_IMPORT = wx.NewId() # create and lay out GUI controls vbox = wx.BoxSizer(wx.VERTICAL) panel = wx.Panel(self, -1) # "About" panel panel1 = wx.Panel(panel, -1) sizer1b = wx.StaticBoxSizer(wx.StaticBox(panel1, -1, 'About this program'), wx.VERTICAL) vbox1 = wx.BoxSizer(wx.VERTICAL) vbox1.Add(wx.StaticText(panel1, -1, "Note importer (c) 2012 Matt Ginzton, [email protected].")) vbox1.Add(wx.StaticText(panel1, -1, "Palm and Evernote may be trademarks of their respective companies.")) vbox1Links = wx.BoxSizer(wx.HORIZONTAL) vbox1Links.Add(wx.StaticText(panel1, -1, "Read the ")) self.usageLink = wx.HyperlinkCtrl(panel1, -1, "usage instructions", "http://www.maddogsw.com/evernote-utilities/evernote-palm-importer/") vbox1Links.Add(self.usageLink) vbox1Links.Add(wx.StaticText(panel1, -1, " to learn how to export your notes from Palm Desktop.")) vbox1.Add(vbox1Links) sizer1b.Add(vbox1, 0, wx.EXPAND) panel1.SetSizer(sizer1b) vbox.Add(panel1, 0, wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM, 15) # Notes-data panel panel2 = wx.Panel(panel, -1) sizer2 = wx.StaticBoxSizer(wx.StaticBox(panel2, -1, 'Palm Desktop note export location'), wx.VERTICAL) sizer2a = wx.BoxSizer(wx.VERTICAL) self.filename = wx.lib.filebrowsebutton.FileBrowseButton(panel2, self.ID_FILEBROWSE, labelText = "Exported file", changeCallback = self.OnExportFileNameChanged) sizer2a.Add(self.filename, 0, wx.EXPAND) sizer2aa = wx.BoxSizer(wx.HORIZONTAL) sizer2aa.Add(wx.StaticText(panel2, -1, "Character encoding")) self.encoding = wx.TextCtrl(panel2, self.ID_ENCODING, details.encoding) sizer2aa.Add(self.encoding, 1, wx.EXPAND) self.encodingLink = wx.HyperlinkCtrl(panel2, -1, "list of valid encodings", "http://docs.python.org/library/codecs.html#standard-encodings") sizer2aa.Add(self.encodingLink) sizer2a.Add(sizer2aa, 0, wx.EXPAND) sizer2ab = wx.BoxSizer(wx.HORIZONTAL) sizer2ab.Add(wx.StaticText(panel2, -1, "Locale used for date parsing")) self.locale = wx.Choice(panel2, self.ID_LOCALE, choices = self.validLocales) self.locale.SetSelection(self.locale.FindString(self.defaultLocale)) sizer2ab.Add(self.locale, 0, wx.EXPAND) sizer2a.Add(sizer2ab, 0, wx.EXPAND) sizer2.Add(sizer2a, 0, wx.EXPAND) panel2.SetSizer(sizer2) vbox.Add(panel2, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 15) # Big-do-it-button panel panel3 = wx.Panel(panel, -1) sizer3 = wx.BoxSizer(wx.HORIZONTAL) self.importButton = wx.Button(panel3, self.ID_IMPORT, "Import notes") sizer3.Add(self.importButton, 3, wx.BOTTOM | wx.EXPAND, 5) self.notesCount = wx.StaticText(panel3, -1, '(0 notes loaded)') sizer3.Add(self.notesCount, 1, wx.BOTTOM | wx.EXPAND, 5) panel3.SetSizer(sizer3) vbox.Add(panel3, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 15) # Operation status panel panel4 = wx.Panel(panel, -1) sizer4 = wx.StaticBoxSizer(wx.StaticBox(panel4, -1, 'Status')) self.statusLabel = wx.ListBox(panel4, self.ID_STATUS) sizer4.Add(self.statusLabel, 1, wx.ALL | wx.EXPAND, 5) self.Report("Instructions: Load a Palm Desktop export file and press Import.") panel4.SetSizer(sizer4) vbox.Add(panel4, 1, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 15) wx.EVT_BUTTON(self, self.ID_IMPORT, self.OnClickImport) wx.EVT_TEXT(self, self.ID_ENCODING, self.OnExportFileEncodingChanged) wx.EVT_CHOICE(self, self.ID_LOCALE, self.OnExportFileLocaleChanged) self.importButton.SetDefault() self.importButton.Enable(False) panel.SetSizer(vbox) vbox.Fit(self) self.Center() self.Show(True) self.importer = PalmNoteImporter(config) self.worker = None self.importing = False self.Connect(-1, -1, PalmImporterUI.THREAD_RESULT_ID, self.OnThreadResult) if details.filename: self.filename.SetValue(details.filename)
class PalmImporterUI(wx.Frame): THREAD_RESULT_ID = wx.NewId() def __init__(self, parent, id, config, details): self.config = config config.interimProgress = self.Report self.InitLocale(details) wx.Frame.__init__(self, parent, id, "Evernote Palm importer") # IDs used for controls we'll interact with more than once self.ID_FILEBROWSE = wx.NewId() self.ID_ENCODING = wx.NewId() self.ID_LOCALE = wx.NewId() self.ID_STATUS = wx.NewId() self.ID_IMPORT = wx.NewId() # create and lay out GUI controls vbox = wx.BoxSizer(wx.VERTICAL) panel = wx.Panel(self, -1) # "About" panel panel1 = wx.Panel(panel, -1) sizer1b = wx.StaticBoxSizer(wx.StaticBox(panel1, -1, 'About this program'), wx.VERTICAL) vbox1 = wx.BoxSizer(wx.VERTICAL) vbox1.Add(wx.StaticText(panel1, -1, "Note importer (c) 2012 Matt Ginzton, [email protected].")) vbox1.Add(wx.StaticText(panel1, -1, "Palm and Evernote may be trademarks of their respective companies.")) vbox1Links = wx.BoxSizer(wx.HORIZONTAL) vbox1Links.Add(wx.StaticText(panel1, -1, "Read the ")) self.usageLink = wx.HyperlinkCtrl(panel1, -1, "usage instructions", "http://www.maddogsw.com/evernote-utilities/evernote-palm-importer/") vbox1Links.Add(self.usageLink) vbox1Links.Add(wx.StaticText(panel1, -1, " to learn how to export your notes from Palm Desktop.")) vbox1.Add(vbox1Links) sizer1b.Add(vbox1, 0, wx.EXPAND) panel1.SetSizer(sizer1b) vbox.Add(panel1, 0, wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM, 15) # Notes-data panel panel2 = wx.Panel(panel, -1) sizer2 = wx.StaticBoxSizer(wx.StaticBox(panel2, -1, 'Palm Desktop note export location'), wx.VERTICAL) sizer2a = wx.BoxSizer(wx.VERTICAL) self.filename = wx.lib.filebrowsebutton.FileBrowseButton(panel2, self.ID_FILEBROWSE, labelText = "Exported file", changeCallback = self.OnExportFileNameChanged) sizer2a.Add(self.filename, 0, wx.EXPAND) sizer2aa = wx.BoxSizer(wx.HORIZONTAL) sizer2aa.Add(wx.StaticText(panel2, -1, "Character encoding")) self.encoding = wx.TextCtrl(panel2, self.ID_ENCODING, details.encoding) sizer2aa.Add(self.encoding, 1, wx.EXPAND) self.encodingLink = wx.HyperlinkCtrl(panel2, -1, "list of valid encodings", "http://docs.python.org/library/codecs.html#standard-encodings") sizer2aa.Add(self.encodingLink) sizer2a.Add(sizer2aa, 0, wx.EXPAND) sizer2ab = wx.BoxSizer(wx.HORIZONTAL) sizer2ab.Add(wx.StaticText(panel2, -1, "Locale used for date parsing")) self.locale = wx.Choice(panel2, self.ID_LOCALE, choices = self.validLocales) self.locale.SetSelection(self.locale.FindString(self.defaultLocale)) sizer2ab.Add(self.locale, 0, wx.EXPAND) sizer2a.Add(sizer2ab, 0, wx.EXPAND) sizer2.Add(sizer2a, 0, wx.EXPAND) panel2.SetSizer(sizer2) vbox.Add(panel2, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 15) # Big-do-it-button panel panel3 = wx.Panel(panel, -1) sizer3 = wx.BoxSizer(wx.HORIZONTAL) self.importButton = wx.Button(panel3, self.ID_IMPORT, "Import notes") sizer3.Add(self.importButton, 3, wx.BOTTOM | wx.EXPAND, 5) self.notesCount = wx.StaticText(panel3, -1, '(0 notes loaded)') sizer3.Add(self.notesCount, 1, wx.BOTTOM | wx.EXPAND, 5) panel3.SetSizer(sizer3) vbox.Add(panel3, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 15) # Operation status panel panel4 = wx.Panel(panel, -1) sizer4 = wx.StaticBoxSizer(wx.StaticBox(panel4, -1, 'Status')) self.statusLabel = wx.ListBox(panel4, self.ID_STATUS) sizer4.Add(self.statusLabel, 1, wx.ALL | wx.EXPAND, 5) self.Report("Instructions: Load a Palm Desktop export file and press Import.") panel4.SetSizer(sizer4) vbox.Add(panel4, 1, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 15) wx.EVT_BUTTON(self, self.ID_IMPORT, self.OnClickImport) wx.EVT_TEXT(self, self.ID_ENCODING, self.OnExportFileEncodingChanged) wx.EVT_CHOICE(self, self.ID_LOCALE, self.OnExportFileLocaleChanged) self.importButton.SetDefault() self.importButton.Enable(False) panel.SetSizer(vbox) vbox.Fit(self) self.Center() self.Show(True) self.importer = PalmNoteImporter(config) self.worker = None self.importing = False self.Connect(-1, -1, PalmImporterUI.THREAD_RESULT_ID, self.OnThreadResult) if details.filename: self.filename.SetValue(details.filename) def InitLocale(self, details): # Build list of locales, and figure out which one is current. A little tricky since perhaps # no locale is current, in which case we need to make the default effective, and there might # be no available default. And either the default or the specified one could be an alias for # a longer name found in the aliases table. self.validLocales = sorted(list(set(locale.locale_alias.values()))) if details.locale and details.locale != "": defLocale = details.locale else: defLocale = locale.getdefaultlocale()[0] if not defLocale: defLocale = "C" # locale.locale_alias uses lowercase keys defLocale = defLocale.lower() # Accept both aliases and real names -- if alias convert to real name, else just assume # it's a real name and woe betide user who specifies something that's neither. if locale.locale_alias.has_key(defLocale): self.defaultLocale = locale.locale_alias[defLocale] else: self.defaultLocale = defLocale def Report(self, status): self.statusLabel.AppendAndEnsureVisible(status) def OnClickImport(self, event): if not self.importing: self.Report("Import process beginning.") self.importButton.SetLabel("Stop importing") self.worker = PalmImporterUI.ImporterThread(self, self.importer) else: self.Report("Cancelling import process.") self.importButton.SetLabel("Cancelling...") self.worker.stop() def OnExportFileNameChanged(self, event): self.OnExportParametersChanged() def OnExportFileEncodingChanged(self, event): self.OnExportParametersChanged() def OnExportFileLocaleChanged(self, event): self.OnExportParametersChanged() def OnExportParametersChanged(self): details = PalmNoteImporter.ExportFileDetails(self.filename.GetValue(), str(self.locale.GetStringSelection()), self.encoding.GetValue()) (result, details) = self.importer.load_notes_file(details) if result: num_notes = details else: self.Report(details) num_notes = 0 self.notesCount.SetLabel('(%d note%s loaded)' % (num_notes, '' if num_notes == 1 else 's')) self.importButton.Enable(num_notes > 0) def OnThreadResult(self, event): (stillGoing, statusMsg) = event.data self.importing = stillGoing self.Report(statusMsg) if not self.importing: self.Report("Import process complete.") self.importButton.SetLabel("Import notes") class ResultEvent(wx.PyEvent): def __init__(self, stillGoing, statusMsg): wx.PyEvent.__init__(self) self.SetEventType(PalmImporterUI.THREAD_RESULT_ID) self.data = [stillGoing, statusMsg] class ImporterThread(Thread): def __init__(self, notifyWindow, importer): Thread.__init__(self) self.notifyWindow = notifyWindow self.importer = importer self.importer.config.canceled = False self.importer.config.interimProgress = self.interimProgress self.start() def interimProgress(self, statusMsg): self.sendProgress(True, statusMsg) def sendProgress(self, stillGoing, statusMsg): # incoming status messages are UTF-8, but UI might not be -- send as Python unicode msg = statusMsg.decode("utf-8") wx.PostEvent(self.notifyWindow, PalmImporterUI.ResultEvent(stillGoing, msg)) def stop(self): self.importer.config.canceled = True def run(self): try: self.sendProgress(True, 'Requesting authentication') self.importer.authenticate_to_evernote() if self.importer.is_authenticated(): result = self.importer.import_notes() else: result = 'Import canceled because authentication was declined or canceled.' self.sendProgress(False, result) except: e = sys.exc_info() traceback.print_exc(file = sys.stderr) self.sendProgress(False, "Unexpected error.")