From 9781b92372f460a1807d6a7b6ac22d565ec62e66 Mon Sep 17 00:00:00 2001 From: Lokno Date: Sun, 31 Aug 2014 10:08:05 -0400 Subject: [PATCH 1/6] Added JSON Save and Load --- app.py | 27 +++++++++++++++----- storyframe.py | 70 +++++++++++++++++++++++++++++++++++++++++---------- storypanel.py | 28 ++++++++++++++++----- tiddlywiki.py | 47 ++++++++++++++++++++++++++++++---- 4 files changed, 142 insertions(+), 30 deletions(-) diff --git a/app.py b/app.py index 1a5a197..ba56fea 100755 --- a/app.py +++ b/app.py @@ -1,7 +1,9 @@ #!/usr/bin/env python2 -import sys, os, locale, re, pickle, wx, platform, traceback +import sys, os, locale, re, simplejson, pickle, jsonpickle, wx, platform, traceback, time import metrics +from tiddlywiki import TiddlyWiki +from tiddlywiki import Tiddler from header import Header from storyframe import StoryFrame from prefframe import PreferenceFrame @@ -33,7 +35,6 @@ def __init__(self, redirect = False): except: pass - # restore save location try: @@ -69,9 +70,10 @@ def removeStory(self, story, byMenu = False): except ValueError: pass - def openDialog(self, event = None): + def openDialog(self, event=None): """Opens a story file of the user's choice.""" - dialog = wx.FileDialog(None, 'Open Story', os.getcwd(), "", "Twine Story (*.tws)|*.tws", \ + fileExtension = "Twine Story (*.tws)|*.tws|JSON Twine Story (*.twjs)|*.twjs" + dialog = wx.FileDialog(None, 'Open Story', os.getcwd(), "", fileExtension, \ wx.FD_OPEN | wx.FD_CHANGE_DIR) if dialog.ShowModal() == wx.ID_OK: @@ -97,14 +99,27 @@ def MacOpenFile(self, path): def open(self, path): """Opens a specific story file.""" try: + usejson = True + if path[len(path)-3:] == "tws": + usejson = False + openedFile = open(path, 'r') - newStory = StoryFrame(None, app = self, state = pickle.load(openedFile)) + fileData = openedFile.read() + openedFile.close() + + if usejson: + state = jsonpickle.decode(fileData) + else: + state = pickle.loads(fileData) + + newStory = StoryFrame(None, app = self, state = state) + newStory.saveDestination = path + self.stories.append(newStory) newStory.Show(True) self.addRecentFile(path) self.config.Write('LastFile', path) - openedFile.close() # weird special case: # if we only had one story opened before diff --git a/storyframe.py b/storyframe.py index f930e9f..71f4058 100644 --- a/storyframe.py +++ b/storyframe.py @@ -1,6 +1,8 @@ -import sys, re, os, urllib, urlparse, pickle, wx, codecs, tempfile, images, version +import sys, re, os, urllib, urlparse, simplejson, pickle, jsonpickle, wx, codecs, tempfile, images, version from wx.lib import imagebrowser from tiddlywiki import TiddlyWiki +from tiddlywiki import Tiddler +import time from storypanel import StoryPanel from passagewidget import PassageWidget from statisticsdialog import StatisticsDialog @@ -8,7 +10,6 @@ from storymetadataframe import StoryMetadataFrame from utils import isURL - class StoryFrame(wx.Frame): """ A StoryFrame displays an entire story. Its main feature is an @@ -90,6 +91,9 @@ def __init__(self, parent, app, state=None, refreshIncludes=True): fileMenu.Append(wx.ID_SAVEAS, 'S&ave Story As...\tCtrl-Shift-S') self.Bind(wx.EVT_MENU, self.saveAs, id=wx.ID_SAVEAS) + fileMenu.Append(StoryFrame.SAVEAS_JSON, 'S&ave Story As (JSON)...') + self.Bind(wx.EVT_MENU, self.saveAsJSON, id=StoryFrame.SAVEAS_JSON) + fileMenu.Append(wx.ID_REVERT_TO_SAVED, '&Revert to Saved') self.Bind(wx.EVT_MENU, self.revert, id=wx.ID_REVERT_TO_SAVED) @@ -486,7 +490,7 @@ def checkCloseDo(self, event, byMenu): elif result == wx.ID_NO: self.dirty = False else: - self.save(None) + self.save() if self.dirty: event.Veto() return @@ -509,10 +513,24 @@ def checkCloseDo(self, event, byMenu): event.Skip() self.Destroy() - def saveAs(self, event=None): + def exportJSON(self, event=None): + self.saveAsMain(True,event) + + def saveAs(self, event=None): + self.saveAsMain(False,event) + + def saveAsJSON(self, event=None): + self.saveAsMain(True,event) + + def saveAsMain(self, usejson=False, event=None): """Asks the user to choose a file to save state to, then passes off control to save().""" + + extensionStr = "Twine Story (*.tws)|*.tws|Twine Story without private content [copy] (*.tws)|*.tws" + if usejson: + extensionStr = "JSON Twine Story (*.twjs)|*.twjs|JSON Twine Story without private content [copy] (*.twjs)|*.twjs" + dialog = wx.FileDialog(self, 'Save Story As', os.getcwd(), "", \ - "Twine Story (*.tws)|*.tws|Twine Story without private content [copy] (*.tws)|*.tws", \ + extensionStr, \ wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT | wx.FD_CHANGE_DIR) if dialog.ShowModal() == wx.ID_OK: @@ -520,13 +538,21 @@ def saveAs(self, event=None): self.saveDestination = dialog.GetPath() self.app.config.Write('savePath', os.getcwd()) self.app.addRecentFile(self.saveDestination) - self.save(None) + self.save(event) elif dialog.GetFilterIndex() == 1: npsavedestination = dialog.GetPath() try: + if usejson: + self.storyPanel.setTimeEncoding(True) + fileData = jsonpickle.encode(self.serialize_noprivate(npsavedestination)) + self.storyPanel.setTimeEncoding(False) + else: + fileData = pickle.dumps(self.serialize_noprivate(npsavedestination)) + dest = open(npsavedestination, 'wb') - pickle.dump(self.serialize_noprivate(npsavedestination), dest) + dest.write(fileData) dest.close() + self.app.addRecentFile(npsavedestination) except: self.app.displayError('saving your story') @@ -819,13 +845,24 @@ def createInfoPassage(self, event): def save(self, event=None): if self.saveDestination == '': - self.saveAs() + self.saveAsMain(False,event) return - try: - dest = open(self.saveDestination, 'wb') - pickle.dump(self.serialize(), dest) + usejson = True + if self.saveDestination[len(self.saveDestination)-3:] == "tws": + usejson = False + + if usejson: + self.storyPanel.setTimeEncoding(True) + fileData = jsonpickle.encode(self.serialize()) + self.storyPanel.setTimeEncoding(False) + else: + fileData = pickle.dumps(self.serialize()) + + dest = open(self.saveDestination, 'wb') + dest.write(fileData) dest.close() + self.setDirty(False) self.app.config.Write('LastFile', self.saveDestination) except: @@ -945,7 +982,7 @@ def getLocalDir(self): dir = os.getcwd() return dir - def readIncludes(self, lines, callback, silent=False): + def readIncludes(self, lines, callback, usejson=True, silent=False): """ Examines all of the source files included via StoryIncludes, and performs a callback on each passage found. @@ -970,9 +1007,14 @@ def readIncludes(self, lines, callback, silent=False): openedFile = open(os.path.join(twinedocdir, line), 'r') if extension == '.tws': - s = StoryFrame(None, app=self.app, state=pickle.load(openedFile), refreshIncludes=False) + fileData = openedFile.read() openedFile.close() + if usejson: + s = StoryFrame(None, app=self.app, state=jsonpickle.decode(fileData), refreshIncludes=False) + else: + s = StoryFrame(None, app=self.app, state=pickle.loads(fileData), refreshIncludes=False) + for widget in s.storyPanel.widgetDict.itervalues(): if excludetags.isdisjoint(widget.passage.tags): callback(widget.passage) @@ -1273,6 +1315,8 @@ def getHeader(self): FILE_EXPORT_SOURCE = 103 FILE_IMPORT_HTML = 104 + SAVEAS_JSON = 1105 + EDIT_FIND_NEXT = 201 VIEW_SNAP = 301 diff --git a/storypanel.py b/storypanel.py index c61c52b..2f69ec4 100644 --- a/storypanel.py +++ b/storypanel.py @@ -1,8 +1,11 @@ from collections import defaultdict from itertools import izip, chain -import sys, wx, re, pickle +import sys, wx, re, jsonpickle, pickle import geometry from tiddlywiki import TiddlyWiki +from tiddlywiki import Tiddler +import simplejson +import time from passagewidget import PassageWidget class StoryPanel(wx.ScrolledWindow): @@ -83,6 +86,11 @@ def __init__(self, parent, app, id = wx.ID_ANY, state = None): self.Bind(wx.EVT_LEAVE_WINDOW, self.handleHoverStop) self.Bind(wx.EVT_MOTION, self.handleHover) + # set whether encode time as a string, or leave it a time.struct_time object for pickling + def setTimeEncoding(self, encodeTime): + for k in self.widgetDict.keys(): + self.widgetDict[k].passage.setTimeEncoding(encodeTime) + def newWidget(self, title = None, text = '', tags = (), pos = None, quietly = False, logicals = False): """Adds a new widget to the container.""" @@ -147,14 +155,18 @@ def toggleSnapping(self): self.snapping = self.snapping is not True self.app.config.WriteBool('storyPanelSnap', self.snapping) - def copyWidgets(self): + def copyWidgets(self, usejson=False): """Copies selected widgets into the clipboard.""" data = [] for widget in self.widgetDict.itervalues(): if widget.selected: data.append(widget.serialize()) clipData = wx.CustomDataObject(wx.CustomDataFormat(StoryPanel.CLIPBOARD_FORMAT)) - clipData.SetData(pickle.dumps(data, 1)) + + if usejson: + clipData.SetData(jsonpickle.encode(data)) + else: + clipData.SetData(pickle.dumps(data, 1)) if wx.TheClipboard.Open(): wx.TheClipboard.SetData(clipData) @@ -166,7 +178,7 @@ def cutWidgets(self): self.removeWidgets() self.Refresh() - def pasteWidgets(self, pos = (0,0), logicals = False): + def pasteWidgets(self, usejson=False, pos = (0,0), logicals = False): """Pastes widgets from the clipboard.""" clipFormat = wx.CustomDataFormat(StoryPanel.CLIPBOARD_FORMAT) clipData = wx.CustomDataObject(clipFormat) @@ -176,7 +188,11 @@ def pasteWidgets(self, pos = (0,0), logicals = False): wx.TheClipboard.Close() if gotData: - data = pickle.loads(clipData.GetData()) + + if usejson: + data = jsonpickle.decode(clipData.GetData()) + else: + data = pickle.loads(clipData.GetData()) self.eachWidget(lambda w: w.setSelected(False, False)) @@ -1073,7 +1089,7 @@ def __init__(self, parent, pos): if self.parent.parent.menus.IsEnabled(wx.ID_PASTE): pastePassage = wx.MenuItem(self, wx.NewId(), 'Paste Passage Here') self.AppendItem(pastePassage) - self.Bind(wx.EVT_MENU, lambda e: self.parent.pasteWidgets(self.getPos()), id = pastePassage.GetId()) + self.Bind(wx.EVT_MENU, lambda e: self.parent.pasteWidgets(True, self.getPos()), id = pastePassage.GetId()) newPassage = wx.MenuItem(self, wx.NewId(), 'New Passage Here') self.AppendItem(newPassage) diff --git a/tiddlywiki.py b/tiddlywiki.py index c38cd83..81ac892 100644 --- a/tiddlywiki.py +++ b/tiddlywiki.py @@ -324,7 +324,7 @@ class Tiddler: # pylint: disable=old-style-class Note: Converting this to a new-style class breaks pickling of new TWS files on old Twine releases. """ - def __init__(self, source, type = 'twee', obfuscatekey = ""): + def __init__(self, source = "", type = 'twee', obfuscatekey = ""): # cache of passage names linked from this one self.links = [] self.displays = [] @@ -338,16 +338,53 @@ def __init__(self, source, type = 'twee', obfuscatekey = ""): self.initHtml(source, obfuscatekey) def __getstate__(self): - """Need to retain pickle format backwards-compatibility with Twine 1.3.5 """ - now = time.localtime() + + # encodes time.struct_time objects if flagged to do so + # adds timeEncoded field to pickle output + # result will not load in an older version of Twine + + ctime = self.created + mtime = self.modified + + timeEncoded = False + + if 'timeEncoded' in self.__dict__: + timeEncoded = self.timeEncoded + + if timeEncoded: + ctime = time.strftime("%m/%d/%Y %H:%M:%S", self.created) + mtime = time.strftime("%m/%d/%Y %H:%M:%S", self.modified) + return { - 'created': now, - 'modified': now, + 'created': ctime, + 'modified': mtime, 'title': self.title, 'tags': self.tags, 'text': self.text, + 'timeEncoded' : timeEncoded, } + def __setstate__(self,d): + self.__dict__ = d + + timeEncoded = False + + if 'timeEncoded' not in self.__dict__: + self.__dict__['timeEncoded'] = False + else: + timeEncoded = self.__dict__['timeEncoded'] + + if timeEncoded: + self.__dict__['created'] = time.strptime(self.__dict__['created'], "%m/%d/%Y %H:%M:%S") + self.__dict__['modified'] = time.strptime(self.__dict__['modified'], "%m/%d/%Y %H:%M:%S") + + def setTimeEncoding(self, encodeTime): + # sets creates the timeEncoded field if it doesn't exist + if 'timeEncoded' not in self.__dict__: + self.__dict__['timeEncoded'] = encodeTime + else: + self.timeEncoded = encodeTime + def __repr__(self): return "" From 96c5c0bc65aabf314f70c4f7162b605608ba54ad Mon Sep 17 00:00:00 2001 From: Lokno Date: Sun, 31 Aug 2014 11:33:50 -0400 Subject: [PATCH 2/6] Removed Time Encoding --- storyframe.py | 4 ---- storypanel.py | 5 ----- tiddlywiki.py | 44 +++++--------------------------------------- 3 files changed, 5 insertions(+), 48 deletions(-) diff --git a/storyframe.py b/storyframe.py index 71f4058..fec264d 100644 --- a/storyframe.py +++ b/storyframe.py @@ -543,9 +543,7 @@ def saveAsMain(self, usejson=False, event=None): npsavedestination = dialog.GetPath() try: if usejson: - self.storyPanel.setTimeEncoding(True) fileData = jsonpickle.encode(self.serialize_noprivate(npsavedestination)) - self.storyPanel.setTimeEncoding(False) else: fileData = pickle.dumps(self.serialize_noprivate(npsavedestination)) @@ -853,9 +851,7 @@ def save(self, event=None): usejson = False if usejson: - self.storyPanel.setTimeEncoding(True) fileData = jsonpickle.encode(self.serialize()) - self.storyPanel.setTimeEncoding(False) else: fileData = pickle.dumps(self.serialize()) diff --git a/storypanel.py b/storypanel.py index 2f69ec4..4a5e63d 100644 --- a/storypanel.py +++ b/storypanel.py @@ -86,11 +86,6 @@ def __init__(self, parent, app, id = wx.ID_ANY, state = None): self.Bind(wx.EVT_LEAVE_WINDOW, self.handleHoverStop) self.Bind(wx.EVT_MOTION, self.handleHover) - # set whether encode time as a string, or leave it a time.struct_time object for pickling - def setTimeEncoding(self, encodeTime): - for k in self.widgetDict.keys(): - self.widgetDict[k].passage.setTimeEncoding(encodeTime) - def newWidget(self, title = None, text = '', tags = (), pos = None, quietly = False, logicals = False): """Adds a new widget to the container.""" diff --git a/tiddlywiki.py b/tiddlywiki.py index 81ac892..6cf88d3 100644 --- a/tiddlywiki.py +++ b/tiddlywiki.py @@ -338,53 +338,19 @@ def __init__(self, source = "", type = 'twee', obfuscatekey = ""): self.initHtml(source, obfuscatekey) def __getstate__(self): - - # encodes time.struct_time objects if flagged to do so - # adds timeEncoded field to pickle output - # result will not load in an older version of Twine - - ctime = self.created - mtime = self.modified - - timeEncoded = False - - if 'timeEncoded' in self.__dict__: - timeEncoded = self.timeEncoded - - if timeEncoded: - ctime = time.strftime("%m/%d/%Y %H:%M:%S", self.created) - mtime = time.strftime("%m/%d/%Y %H:%M:%S", self.modified) - + """Need to retain pickle format backwards-compatibility with Twine 1.3.5 """ + now = time.localtime() return { - 'created': ctime, - 'modified': mtime, + 'created': now, + 'modified': now, 'title': self.title, 'tags': self.tags, - 'text': self.text, - 'timeEncoded' : timeEncoded, + 'text': self.text } def __setstate__(self,d): self.__dict__ = d - timeEncoded = False - - if 'timeEncoded' not in self.__dict__: - self.__dict__['timeEncoded'] = False - else: - timeEncoded = self.__dict__['timeEncoded'] - - if timeEncoded: - self.__dict__['created'] = time.strptime(self.__dict__['created'], "%m/%d/%Y %H:%M:%S") - self.__dict__['modified'] = time.strptime(self.__dict__['modified'], "%m/%d/%Y %H:%M:%S") - - def setTimeEncoding(self, encodeTime): - # sets creates the timeEncoded field if it doesn't exist - if 'timeEncoded' not in self.__dict__: - self.__dict__['timeEncoded'] = encodeTime - else: - self.timeEncoded = encodeTime - def __repr__(self): return "" From 7c8a8627b490f47e1b66b0700efae67a07842da2 Mon Sep 17 00:00:00 2001 From: Lokno Date: Sun, 31 Aug 2014 13:45:47 -0400 Subject: [PATCH 3/6] Added regex to remove time fields from JSON output --- app.py | 2 +- storyframe.py | 2 ++ storypanel.py | 18 +++++++++++++++++- tiddlywiki.py | 4 +++- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app.py b/app.py index ba56fea..7d795e1 100755 --- a/app.py +++ b/app.py @@ -110,7 +110,7 @@ def open(self, path): if usejson: state = jsonpickle.decode(fileData) else: - state = pickle.loads(fileData) + state = pickle.loads(fileData) newStory = StoryFrame(None, app = self, state = state) diff --git a/storyframe.py b/storyframe.py index fec264d..bc3fb96 100644 --- a/storyframe.py +++ b/storyframe.py @@ -544,6 +544,7 @@ def saveAsMain(self, usejson=False, event=None): try: if usejson: fileData = jsonpickle.encode(self.serialize_noprivate(npsavedestination)) + fileData = self.storyPanel.stripTimeFields( fileData ) else: fileData = pickle.dumps(self.serialize_noprivate(npsavedestination)) @@ -852,6 +853,7 @@ def save(self, event=None): if usejson: fileData = jsonpickle.encode(self.serialize()) + fileData = self.storyPanel.stripTimeFields( fileData ) else: fileData = pickle.dumps(self.serialize()) diff --git a/storypanel.py b/storypanel.py index 4a5e63d..40a81b4 100644 --- a/storypanel.py +++ b/storypanel.py @@ -8,6 +8,18 @@ import time from passagewidget import PassageWidget +# r + s1 + r + s2 + r + ... + sn + r +def unfoldPattern(s,r): + pat = '' + e = '[]{}.?*^+-' + for c in s: + pat += r + if c in e: + pat += '\\' + pat += c + pat += r + return pat + class StoryPanel(wx.ScrolledWindow): """ A StoryPanel is a container for PassageWidgets. It translates @@ -48,6 +60,7 @@ def __init__(self, parent, app, id = wx.ID_ANY, state = None): self.tooltipplace = None self.tooltipobj = None self.textDragSource = None + self.timeFields = re.compile(',?[^\{\}\[\],]*"(created|modified)": (' + unfoldPattern('{,[{},{[{[,,,,,,,,]},{}]}]}', '[^\{\}\[\],]*') + '|\{[^\{\}]+\})') if state: self.scale = state['scale'] @@ -86,6 +99,9 @@ def __init__(self, parent, app, id = wx.ID_ANY, state = None): self.Bind(wx.EVT_LEAVE_WINDOW, self.handleHoverStop) self.Bind(wx.EVT_MOTION, self.handleHover) + def stripTimeFields( self, s ): + return self.timeFields.sub('',s) + def newWidget(self, title = None, text = '', tags = (), pos = None, quietly = False, logicals = False): """Adds a new widget to the container.""" @@ -159,7 +175,7 @@ def copyWidgets(self, usejson=False): clipData = wx.CustomDataObject(wx.CustomDataFormat(StoryPanel.CLIPBOARD_FORMAT)) if usejson: - clipData.SetData(jsonpickle.encode(data)) + clipData.SetData( self.stripTimeFields( jsonpickle.encode(data) ) ) else: clipData.SetData(pickle.dumps(data, 1)) diff --git a/tiddlywiki.py b/tiddlywiki.py index 6cf88d3..008d6e4 100644 --- a/tiddlywiki.py +++ b/tiddlywiki.py @@ -331,6 +331,8 @@ def __init__(self, source = "", type = 'twee', obfuscatekey = ""): self.images = [] self.macros = [] + self.addDate = True + """Pass source code, and optionally 'twee' or 'html'""" if type == 'twee': self.initTwee(source) @@ -346,7 +348,7 @@ def __getstate__(self): 'title': self.title, 'tags': self.tags, 'text': self.text - } + } def __setstate__(self,d): self.__dict__ = d From f66fbeaf7930fb18dd42218fc0239a4ea2829b4c Mon Sep 17 00:00:00 2001 From: Lokno Date: Sun, 31 Aug 2014 13:53:22 -0400 Subject: [PATCH 4/6] Removed unused variable addDate --- tiddlywiki.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tiddlywiki.py b/tiddlywiki.py index 008d6e4..6cf88d3 100644 --- a/tiddlywiki.py +++ b/tiddlywiki.py @@ -331,8 +331,6 @@ def __init__(self, source = "", type = 'twee', obfuscatekey = ""): self.images = [] self.macros = [] - self.addDate = True - """Pass source code, and optionally 'twee' or 'html'""" if type == 'twee': self.initTwee(source) @@ -348,7 +346,7 @@ def __getstate__(self): 'title': self.title, 'tags': self.tags, 'text': self.text - } + } def __setstate__(self,d): self.__dict__ = d From d1a68c5d7d427bd306db2a123a10a70ddc46b3ef Mon Sep 17 00:00:00 2001 From: Lokno Date: Sun, 31 Aug 2014 18:52:23 -0400 Subject: [PATCH 5/6] Removed JSON pickling from copy/paste methods. --- storypanel.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/storypanel.py b/storypanel.py index 40a81b4..187cea7 100644 --- a/storypanel.py +++ b/storypanel.py @@ -1,10 +1,8 @@ from collections import defaultdict from itertools import izip, chain -import sys, wx, re, jsonpickle, pickle +import sys, wx, re, pickle import geometry from tiddlywiki import TiddlyWiki -from tiddlywiki import Tiddler -import simplejson import time from passagewidget import PassageWidget @@ -166,7 +164,7 @@ def toggleSnapping(self): self.snapping = self.snapping is not True self.app.config.WriteBool('storyPanelSnap', self.snapping) - def copyWidgets(self, usejson=False): + def copyWidgets(self): """Copies selected widgets into the clipboard.""" data = [] for widget in self.widgetDict.itervalues(): @@ -174,10 +172,7 @@ def copyWidgets(self, usejson=False): clipData = wx.CustomDataObject(wx.CustomDataFormat(StoryPanel.CLIPBOARD_FORMAT)) - if usejson: - clipData.SetData( self.stripTimeFields( jsonpickle.encode(data) ) ) - else: - clipData.SetData(pickle.dumps(data, 1)) + clipData.SetData(pickle.dumps(data, 1)) if wx.TheClipboard.Open(): wx.TheClipboard.SetData(clipData) @@ -189,7 +184,7 @@ def cutWidgets(self): self.removeWidgets() self.Refresh() - def pasteWidgets(self, usejson=False, pos = (0,0), logicals = False): + def pasteWidgets(self, pos = (0,0), logicals = False): """Pastes widgets from the clipboard.""" clipFormat = wx.CustomDataFormat(StoryPanel.CLIPBOARD_FORMAT) clipData = wx.CustomDataObject(clipFormat) @@ -200,10 +195,7 @@ def pasteWidgets(self, usejson=False, pos = (0,0), logicals = False): if gotData: - if usejson: - data = jsonpickle.decode(clipData.GetData()) - else: - data = pickle.loads(clipData.GetData()) + data = pickle.loads(clipData.GetData()) self.eachWidget(lambda w: w.setSelected(False, False)) @@ -1100,7 +1092,7 @@ def __init__(self, parent, pos): if self.parent.parent.menus.IsEnabled(wx.ID_PASTE): pastePassage = wx.MenuItem(self, wx.NewId(), 'Paste Passage Here') self.AppendItem(pastePassage) - self.Bind(wx.EVT_MENU, lambda e: self.parent.pasteWidgets(True, self.getPos()), id = pastePassage.GetId()) + self.Bind(wx.EVT_MENU, lambda e: self.parent.pasteWidgets(self.getPos()), id = pastePassage.GetId()) newPassage = wx.MenuItem(self, wx.NewId(), 'New Passage Here') self.AppendItem(newPassage) From 9a1a0f98c847a55534cd31d2f29ab195aaea48a4 Mon Sep 17 00:00:00 2001 From: Lokno Date: Tue, 30 Sep 2014 00:39:47 -0400 Subject: [PATCH 6/6] Added specifications to jsonpickle in app.py to sort and indent the output JSON; modified regex for stripping out time codes to match changes. --- app.py | 2 ++ storypanel.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app.py b/app.py index 7d795e1..82fc327 100755 --- a/app.py +++ b/app.py @@ -30,6 +30,8 @@ def __init__(self, redirect = False): self.icon = wx.EmptyIcon() + jsonpickle.set_encoder_options('simplejson', sort_keys=True, indent=4) + try: self.icon = wx.Icon(self.iconsPath + 'app.ico', wx.BITMAP_TYPE_ICO) except: diff --git a/storypanel.py b/storypanel.py index 187cea7..eac82dc 100644 --- a/storypanel.py +++ b/storypanel.py @@ -58,8 +58,8 @@ def __init__(self, parent, app, id = wx.ID_ANY, state = None): self.tooltipplace = None self.tooltipobj = None self.textDragSource = None - self.timeFields = re.compile(',?[^\{\}\[\],]*"(created|modified)": (' + unfoldPattern('{,[{},{[{[,,,,,,,,]},{}]}]}', '[^\{\}\[\],]*') + '|\{[^\{\}]+\})') - + #self.timeFields = re.compile(',?[^\{\}\[\],]*"(created|modified)": (' + unfoldPattern('{,[{},{[{[,,,,,,,,]},{}]}]}', '[^\{\}\[\],]*') + '|\{[^\{\}]+\})') + self.timeFields = re.compile('[^\{\}\[\],]*"(created|modified)": (' + unfoldPattern('{[{},{[{[,,,,,,,,]},{}]}],}', '[^\{\}\[\],]*') + '|\{[^\{\}]+\}),?') if state: self.scale = state['scale'] for widget in state['widgets']: