def __init__(self, parent, document): self.parent = parent self.notebook = None self.model = ZBlogPostEditorModel() self.model.setDocument(document) self.wysiwygContentEditor = None self.xhtmlContentEditor = None self.contentPreviewer = None self.activeContentEditor = None self.previewMode = False self.currentPreviewTemplate = None self.dataStoreService = getApplicationModel().getService(IZBlogAppServiceIDs.DATA_STORE_SERVICE_ID) self.templateService = getApplicationModel().getService(IZBlogAppServiceIDs.TEMPLATE_SERVICE_ID) ZEditor.__init__(self, parent) self.bitmap = self._createEditorBitmap() self.menuBarModel = self._createMenuBarModel() self.toolBarModel = self._createToolBarModel() self.statusBarModel = self._createStatusBarModel() self._registerAsListener() self._startSnapshotTimer()
class ZBlogPostEditor(ZEditor, IZDataStoreListener, IZTemplateServiceListener): def __init__(self, parent, document): self.parent = parent self.notebook = None self.model = ZBlogPostEditorModel() self.model.setDocument(document) self.wysiwygContentEditor = None self.xhtmlContentEditor = None self.contentPreviewer = None self.activeContentEditor = None self.previewMode = False self.currentPreviewTemplate = None self.dataStoreService = getApplicationModel().getService(IZBlogAppServiceIDs.DATA_STORE_SERVICE_ID) self.templateService = getApplicationModel().getService(IZBlogAppServiceIDs.TEMPLATE_SERVICE_ID) ZEditor.__init__(self, parent) self.bitmap = self._createEditorBitmap() self.menuBarModel = self._createMenuBarModel() self.toolBarModel = self._createToolBarModel() self.statusBarModel = self._createStatusBarModel() self._registerAsListener() self._startSnapshotTimer() # end __init__() def getActiveContentEditor(self): return self.activeContentEditor # end getActiveContentEditor() def _setActiveContentEditor(self, editor): if not (editor == self.wysiwygContentEditor or editor == self.xhtmlContentEditor): return # FIXME (PJ) switch only if content is dirty i.e. not to lose current selection info, and cursor/caret position etc. # copy current editor ui data (including xhtml content) to the model self._updateModel() # switch editors self.activeContentEditor = editor # update ui based on model data self._refreshContentEditorUI() # end _setActiveContentEditor() def _updateModel(self): # update model data based on current ui data. self.getActiveContentEditor().updateModel() # end _updateModel() def _refreshContentEditorUI(self): # update ui based on current model data self.getActiveContentEditor().refreshUI() # end _refreshContentEditorUI() def _showPreview(self): xhtmlDoc = self.getActiveContentEditor()._getContentEditControl().getXhtmlDocument() # Get the current blog selection from the UI control. if self.currentPreviewTemplate is not None: document = ZBlogPostEditorPreviewDocument(self.getTitle(), xhtmlDoc) templatedDoc = applyTemplateToDocument(self.currentPreviewTemplate, document, APPLY_TEMPLATE_MODE_FULL) if templatedDoc is not None: xhtmlDoc = templatedDoc disableTemplatePreviewJavaScript(xhtmlDoc) self.contentPreviewer.setXhtmlDocument(xhtmlDoc, False) # end _showPreview() def _isWysiwygActive(self): return self.previewMode == False and self.activeContentEditor is not None and self.activeContentEditor == self.wysiwygContentEditor # end _isWysiwygActive() def _isXhtmlActive(self): return self.previewMode == False and self.activeContentEditor is not None and self.activeContentEditor == self.xhtmlContentEditor # end _isXhtmlActive() def _isPreviewActive(self): return self.previewMode # end _isPreviewActive() def getTitle(self): return self.model.getTitle() # end getTitle() def getBitmap(self): return self.bitmap # end getBitmap() def getMenuBarModel(self): return self.menuBarModel # end getMenuBarModel() def getToolBarModel(self): return self.toolBarModel # end getToolBarModel() def getStatusBarModel(self): return self.statusBarModel # end getStatusBarModel() def getDocumentId(self): return self.model.getDocument().getId() # end getDocumentId() def getDocument(self): return self.model.getDocument() # end getDocument() def getToolBarActionContext(self): return ZBlogPostEditorToolBarActionContext(self) # end getToolBarActionContext() def getMenuActionContext(self): return ZBlogPostEditorMenuActionContext(self) # end getMenuActionContext def getAcceleratorActionContext(self): return ZBlogPostEditorMenuActionContext(self) # end getAcceleratorActionContext def save(self): self._clearRecoverySnapshot() # Flush data from UI controls to document model self._updateModel() portableFilesCopies = self._checkForNonPortableFiles() # save model documen to data store self.model.saveDocument() self.getActiveContentEditor().modelSaved() self.setDirty(False) if portableFilesCopies: # refresh editor UI if files were copies to the portable profile resource store self.getActiveContentEditor().refreshUI() # end save() def _checkForNonPortableFiles(self): xhtmlDoc = self.getDocument().getContent().getXhtmlDocument() # This method copies non portable files/images to resource store and updates the img src (href) attribute values. # Returns true if files were copies. return copyNonPortableFiles(self, xhtmlDoc) # end _checkForNonPortableFiles def close(self): pass # end close() def destroy(self): self._stopSnapshotTimer() self._unregisterAsListener() self._clearRecoverySnapshot() # end destroy() def hasCapability(self, capabilityKey): #@UnusedVariable if not self._isPreviewActive(): # delegate to the content editor's edit control return self.getActiveContentEditor().hasCapability(capabilityKey) else: return False # end hasCapability() def _createMenuBarModel(self): return ZBlogPostEditorMenuBarModel(self) # end getMenuBarModel() def _createToolBarModel(self): return ZBlogPostEditorToolBarModel() # end _createToolBarModel() def _createStatusBarModel(self): # FIXME (PJ) need a proper implementation of the status bar model, this is just a sample # Instead showing datetime, show word count, current tag name etc. sbModel = ZStatusBarModel() pane = sbModel.addPane(u"datetime") #$NON-NLS-1$ pane.text = formatLocalDateAndTime( self.model.getDocument().getCreationTime() ) pane = sbModel.addPane(u"rowcol") #$NON-NLS-1$ sbModel.setPaneWidth(u"rowcol", 80) #$NON-NLS-1$ pane.text = u"" #$NON-NLS-1$ return sbModel # end _createStatusBarModel() def _createEditorWidgets(self): self._createAcceleratorTable() self.notebook = fnb.FlatNotebook(self, wx.ID_ANY, style = fnb.FNB_BOTTOM | fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NO_X_BUTTON | fnb.FNB_NODRAG) self.notebook.AddPage(self._createWysiwygPage(), _extstr(u"blogeditor.Design"), True, -1) #$NON-NLS-1$ self.notebook.AddPage(self._createXHTMLPage(), _extstr(u"blogeditor.XHTML"), False, -1) #$NON-NLS-1$ self.notebook.AddPage(self._createPreviewPage(), _extstr(u"blogeditor.Preview"), False, -1) #$NON-NLS-1$ # end _createEditorWidgets() def _createWysiwygPage(self): self.wysiwygContentEditor = ZBlogPostContentEditorFactory().createContentWysiwygEditor(self.notebook, self, self.model) return self.wysiwygContentEditor # end _createDesignPage() def _createXHTMLPage(self): self.xhtmlContentEditor = ZBlogPostContentEditorFactory().createContentXhtmlEditor(self.notebook, self, self.model) self.xhtmlContentEditor.SetBackgroundColour(wx.WHITE) return self.xhtmlContentEditor # end _createXHTMLPage() def _createPreviewPage(self): self.previewTabPanel = ZTransparentPanel(self.notebook, wx.ID_ANY) self._createPreviewTools(self.previewTabPanel) self.contentPreviewer = ZBlogPostContentEditorFactory().createContentPreviewer(self.previewTabPanel, self, self.model) self.contentPreviewer.SetBackgroundColour(wx.WHITE) return self.previewTabPanel # end _createPreviewPage() def _createPreviewTools(self, parent): self.templateChooseLabel = wx.StaticText(parent, wx.ID_ANY, _extstr(u"blogeditor.ViewWithTemplate")) #$NON-NLS-1$ self.templateChooser = wx.combo.BitmapComboBox(parent, wx.ID_ANY, style = wx.CB_READONLY) self.previewStaticLine = wx.StaticLine(parent, wx.ID_ANY) # end _createPreviewTools() def _createAcceleratorTable(self): self.acceleratorTable = ZBlogPostEditorAcceleratorTable(self.getAcceleratorActionContext()) self.SetAcceleratorTable(self.acceleratorTable) # end _createAcceleratorTable() def _populateEditorWidgets(self): self.activeContentEditor = self.wysiwygContentEditor self._refreshContentEditorUI() self._updateTemplateUI() # end _populateEditorWidgets() def _updateTemplateUI(self): blog = self._getBlog() self.currentPreviewTemplate = None currentTemplateId = None if blog is not None: templateId = blog.getTemplateId() if templateId is not None: currentTemplateId = templateId template = self.templateService.getTemplate(templateId) if template: self.currentPreviewTemplate = template self._updateTemplateChooser(currentTemplateId) # end _updateTemplateUI() def _updateTemplateChooser(self, currentTemplateId = None): if currentTemplateId is None and self.currentPreviewTemplate is not None: currentTemplateId = self.currentPreviewTemplate.getId() self.templateChooser.Clear() bitmap = getResourceRegistry().getBitmap(u"images/dialogs/template/manager/template.png") #$NON-NLS-1$ self.templateChooser.Append(_extstr(u"blogeditor.__NoTemplate__"), wx.NullBitmap, u"_no_template_") #$NON-NLS-2$ #$NON-NLS-1$ idx = 1 for template in self.templateService.getTemplates(): self.templateChooser.Append(template.getName(), bitmap, template.getId()) if template.getId() == currentTemplateId: self.templateChooser.Select(idx) idx = idx + 1 (w, h) = self.templateChooser.GetBestSizeTuple() self.templateChooser.SetMinSize(wx.Size(w + 18, h)) if currentTemplateId is None: self.templateChooser.Select(0) # end _updateTemplateUI() def _layoutEditorWidgets(self): self._layoutPreviewWidgets() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.notebook, 1, wx.EXPAND) return sizer # end _layoutEditorWidgets() def _layoutPreviewWidgets(self): chooserSizer = wx.BoxSizer(wx.HORIZONTAL) chooserSizer.Add(self.templateChooseLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 3) chooserSizer.Add(self.templateChooser, 0, wx.ALL, 3) sizer = wx.BoxSizer(wx.VERTICAL) sizer.AddSizer(chooserSizer, 0, wx.ALL | wx.EXPAND) sizer.Add(self.previewStaticLine, 0, wx.ALL | wx.EXPAND) sizer.Add(self.contentPreviewer, 1, wx.ALL | wx.EXPAND) self.previewTabPanel.SetSizer(sizer) self.previewTabPanel.SetAutoLayout(True) # end _layoutPreviewWidgets() def _bindWidgetEvents(self): self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGING, self.onTabChanging) self.Bind(fnb.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.onTabChanged) self.Bind(ZEVT_PUBLISHING_CHANGE, self.onPublishingChange) self.Bind(ZEVT_META_DATA_TITLE_CHANGED, self.onTitleChanged) self.Bind(wx.EVT_COMBOBOX, self.onTemplateChooser, self.templateChooser) self.acceleratorTable.bindTo(self) # end _bindWidgetEvents() def _setInitialFocus(self): document = self.getDocument() title = document.getTitle() if title: self.getActiveContentEditor().focusOnContent() # end _setInitialFocus() def _createEditorBitmap(self): # FIXME (EPW) change the icon for blog posts return getApplicationModel().getResourceRegistry().getBitmap(u"images/mainapp/icon/icon16x16.png") #$NON-NLS-1$ # end _createEditorBitmap() def onTabChanging(self, event): editorTabId = event.GetSelection() self.previewMode = False # switch to wysiwyg if editorTabId == 0 and not self._isWysiwygActive(): self._setActiveContentEditor(self.wysiwygContentEditor) # switch to xthml text editor elif editorTabId == 1 and not self._isXhtmlActive(): self._setActiveContentEditor(self.xhtmlContentEditor) elif editorTabId == 2: self.previewMode = True self._updateModel() self._updateTemplateUI() self._showPreview() # clear (row, col) text in status bar for preview control self.statusBarModel.setPaneText(u"rowcol", u"") #$NON-NLS-1$ #$NON-NLS-2$ # update toolbar (e.g. disable paste, cut actions ) self._fireToolBarChangedEvent() self._fireMenuBarChangedEvent() self._fireStatusBarChangedEvent() # end onTabChanging() def onTabChanged(self, event): event.Skip() # end onTabChanged() def onTitleChanged(self, event): self.model.setTitle(event.getTitle()) self._fireTitleChangedEvent() event.Skip() # end onTitleChanged() def onPublishingChange(self, event): self.setDirty(True) event.Skip() # end onPublishingChange() def onMenuClose(self, menuContext): #@UnusedVariable self._fireCloseEvent() # end onMenuClose() # Likely to happen on a separate thread... def onDocumentChanged(self, document, metaDataOnly): if document.getId() == self.getDocumentId(): if metaDataOnly: modelDoc = self.getDocument() modelDoc.setBlogInfoList(document.getBlogInfoList()) self._fireUpdateMenu() elif not self.isDirty(): self.model.setDocument(document) fireUIExecEvent(ZMethodRunnable(self._refreshContentEditorUI), self) else: # FIXME (EPW) Editor is dirty, but content changes were made by someone else - prompt the user for what to do pass # end onDocumentChanged() def onDocumentDeleted(self, document): u"Called when a specific document has been deleted." #$NON-NLS-1$ # Note: we should probably do something interesting if the document we are currently # editing was deleted. # end onDocumentDeleted() def onTemplateCreated(self, template): #@UnusedVariable self._updateTemplateChooser() # end onTemplateCreated() def onTemplateDeleted(self, template): #@UnusedVariable if self.currentPreviewTemplate is not None: if template.getId() == self.currentPreviewTemplate.getId(): self.currentPreviewTemplate = None self._updateTemplateUI() self._showPreview() return self._updateTemplateChooser() # end onTemplateDeleted() def onTemplateModified(self, template): #@UnusedVariable self._updateTemplateChooser() # end onTemplateModified() def _fireDirtyEvent(self): ZEditor._fireDirtyEvent(self) self._fireUpdateMenu() # end _fireDirtyEvent(); def _fireUpdateMenu(self): self._fireMenuBarChangedEvent() self._fireToolBarChangedEvent() # end _fireUpdateMenu(); def _registerAsListener(self): self.dataStoreService.addListener(self) self.templateService.addListener(self) # end _registerAsListener() def _unregisterAsListener(self): self.dataStoreService.removeListener(self) self.templateService.removeListener(self) # end _unregisterAsListener() def _startSnapshotTimer(self): self.snapshotTimerId = wx.NewId() self.snapshotTimer = wx.Timer(self, self.snapshotTimerId) wx.EVT_TIMER(self, self.snapshotTimerId, self.onSnapshotTimer) # Timer will fire every 60 seconds self.snapshotTimer.Start(60000) # end _startSnapshotTimer() def _stopSnapshotTimer(self): self.snapshotTimer.Stop() # end _stopSnapshotTimer() def _clearRecoverySnapshot(self): document = self.getDocument() crashRecoveryService = getApplicationModel().getService(IZBlogAppServiceIDs.CRASH_RECOVERY_SERVICE_ID) crashRecoveryService.clearRecoverySnapshot(document) # end _clearRecoverySnapshot() def _takeRecoverySnapshot(self): try: self._updateModel() document = self.getDocument() crashRecoveryService = getApplicationModel().getService(IZBlogAppServiceIDs.CRASH_RECOVERY_SERVICE_ID) crashRecoveryService.takeRecoverySnapshot(document) except Exception, e: getLoggerService().exception(e)