def __init__(self, parent=None): QtGui.QMainWindow.__init__(self, parent) self.setMinimumSize(500, 400) self.showMaximized() self.setWindowTitle("Second Nature") self.setWindowFlags(QtCore.Qt.Window) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.logger = sn_logger self.__applets = [] self.__extInitialised = False # -- main menu bar -- self._mainMenuBar = QtGui.QMenuBar(self) self._projectMenu = self._mainMenuBar.addMenu("&Project") self.setMenuBar(self._mainMenuBar) # -- project menu -- qpm = QActiveProjectManager() self._projectMenu.addAction(qpm.get_action_new()) self._projectMenu.addAction(qpm.get_action_open()) self._projectMenu.addAction(qpm.get_action_save()) self._projectMenu.addAction(qpm.get_action_close()) # -- a default central widget-- self.__centralStack = QtGui.QStackedWidget(self) # -- status bar -- self._statusBar = QtGui.QStatusBar(self) self._layoutMode = QtGui.QComboBox(self) self._statusBar.addPermanentWidget(self._layoutMode) self._layoutMode.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) self.__currentLayout = None self._statusBar.setStyleSheet("QStatusBar{background-color: " +\ "qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, "+\ "stop:0 rgba(135,135,135,255), " +\ "stop:0.1 rgba(175,175,175,255), " +\ "stop:1 rgba(200, 200, 200, 255));}") # -- add all those guys to the main window (self) -- self.setMenuBar(self._mainMenuBar) self.setStatusBar(self._statusBar) self.setCentralWidget(self.__centralStack) self.__projMan = ProjectManager() if not self.__projMan.has_active_project(): self.__projMan.new_active_project("New Project") # -- connections -- self.__projMan.active_project_changed.connect(self.__on_active_project_set) AppletFactoryManager().applet_created.connect(self.add_applet) LayoutManager().item_list_changed.connect(self.__onLayoutListChanged) self._layoutMode.activated[int].connect(self.__onLayoutChosen) self._layoutMode.currentIndexChanged[int].connect(self.__onLayoutChosen)
def __init__(self, parent=None): QtGui.QStandardItemModel.__init__(self, parent) self.__projMan = ProjectManager() self.__docItemMap = {} self.__activeProjItem = None self.itemChanged.connect(self.__on_item_changed) self.__projMan.active_project_changed.connect(self.set_active_project) self.__activeProj = None activePrj = self.__projMan.get_active_project() if activePrj: self.set_active_project(activePrj)
class SiblingList(object): def __init__(self, mimetype): self.mimetype = mimetype self.projMan = ProjectManager() def __iter__(self): activeProj = self.projMan.get_active_project() for id, data in activeProj: print data.mimetype if data.mimetype == self.mimetype: yield data.obj
def _new_0(self): data = self.new() if data.registerable: ProjectManager().add_data_to_active_project(data) return data
def __init__(self, mimetype): self.mimetype = mimetype self.projMan = ProjectManager()
def _open_url_0(self, parsedUrl): data = self.open_url(parsedUrl) if data.registerable: ProjectManager().add_data_to_active_project(data) return data
class MainWindow(QtGui.QMainWindow): def __init__(self, parent=None): QtGui.QMainWindow.__init__(self, parent) self.setMinimumSize(500, 400) self.showMaximized() self.setWindowTitle("Second Nature") self.setWindowFlags(QtCore.Qt.Window) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.logger = sn_logger self.__applets = [] self.__extInitialised = False # -- main menu bar -- self._mainMenuBar = QtGui.QMenuBar(self) self._projectMenu = self._mainMenuBar.addMenu("&Project") self.setMenuBar(self._mainMenuBar) # -- project menu -- qpm = QActiveProjectManager() self._projectMenu.addAction(qpm.get_action_new()) self._projectMenu.addAction(qpm.get_action_open()) self._projectMenu.addAction(qpm.get_action_save()) self._projectMenu.addAction(qpm.get_action_close()) # -- a default central widget-- self.__centralStack = QtGui.QStackedWidget(self) # -- status bar -- self._statusBar = QtGui.QStatusBar(self) self._layoutMode = QtGui.QComboBox(self) self._statusBar.addPermanentWidget(self._layoutMode) self._layoutMode.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) self.__currentLayout = None self._statusBar.setStyleSheet("QStatusBar{background-color: " +\ "qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, "+\ "stop:0 rgba(135,135,135,255), " +\ "stop:0.1 rgba(175,175,175,255), " +\ "stop:1 rgba(200, 200, 200, 255));}") # -- add all those guys to the main window (self) -- self.setMenuBar(self._mainMenuBar) self.setStatusBar(self._statusBar) self.setCentralWidget(self.__centralStack) self.__projMan = ProjectManager() if not self.__projMan.has_active_project(): self.__projMan.new_active_project("New Project") # -- connections -- self.__projMan.active_project_changed.connect(self.__on_active_project_set) AppletFactoryManager().applet_created.connect(self.add_applet) LayoutManager().item_list_changed.connect(self.__onLayoutListChanged) self._layoutMode.activated[int].connect(self.__onLayoutChosen) self._layoutMode.currentIndexChanged[int].connect(self.__onLayoutChosen) def init_extensions(self): self.setEnabled(False) AbstractSourceManager.init() # --choosing default layout-- index = self._layoutMode.findText("Default Layout") if index >= 0: self._layoutMode.setCurrentIndex(index) self.__extInitialised = True self.setEnabled(True) extensions_initialised = property(lambda x:x.__extInitialised) def get_datafactory_menu(self): datafactories = [f for f in DataFactoryManager().gather_items().itervalues() \ if not f.singleton] # lambda x,y:cmp(x.name, y.name)) menu = QtGui.QMenu(self) for dt in datafactories: action = menu.addAction(dt.icon, "New "+dt.name) action.setIconVisibleInMenu(True) func = self.__make_datafactory_chosen_handler(dt) action.triggered.connect(func) return menu def __make_datafactory_chosen_handler(self, dt): def on_datafactory_chosen(checked): data = dt._new_0() return on_datafactory_chosen ######################################### # Active project status change handlers # ######################################### def __on_active_project_set(self, proj, old): for applet in self.__applets: # if old: # try_to_disconnect(old.data_added, applet.update_combo_list) proj.data_added.connect(applet.update_combo_list) applet.project = proj proj.closed.connect(self.__on_active_project_closed) def __on_active_project_closed(self, proj): for applet in self.__applets: try_to_disconnect(proj.data_added, applet.update_combo_list) def add_applet(self, applet): self.__projMan.data_added.connect(applet.update_combo_list) self.__applets.append(applet) ################################# # DRAG AND DROP RELATED METHODS # ################################# def __validate_mimedata(self, mimedata): good = False if mimedata.hasFormat("text/uri-list"): urls = mimedata.urls() # we only support ONE url if len(urls) == 1: good = True elif mimedata.hasFormat(ProjectManager.mimeformat): good = True if not good: self.logger.error("unknown mimedata: "+ str([str(f) for f in mimedata.formats()])) return good def __on_splitter_drag_enter(self, splittable, event): mimeData = event.mimeData() if not self.__validate_mimedata(mimeData): return formats = map(str, mimeData.formats()) handlers = DataFactoryManager().get_handlers_for_mimedata(formats) if len(handlers) > 0: event.acceptProposedAction() elif mimeData.hasFormat(ProjectManager.mimeformat): event.acceptProposedAction() def __on_splitter_pane_drop(self, splittable, paneId, event): mimeData = event.mimeData() if not self.__validate_mimedata(mimeData): return proj = self.__projMan.get_active_project() app = None data = None content = None space = None if mimeData.hasUrls(): formats = mimeData.formats() url = str(mimeData.urls()[0]) dt = DataEditorSelector.mime_type_handler(formats, applet=False) if not dt: return parsedUrl = urlparse.urlparse(url) data = dt._open_url_0(parsedUrl) if not data: return app = DataEditorSelector.mime_type_handler([data.mimetype], applet=True) if not app: return elif mimeData.hasFormat(ProjectManager.mimeformat): print "projectmanager drop" dataIdBytes = mimeData.data(ProjectManager.mimeformat) if dataIdBytes: dataId, ok = dataIdBytes.toInt() if ok and proj: data = proj.get_data(dataId) if data: app = DataEditorSelector.mime_type_handler([data.mimetype], applet=True) print "got applet", app.name # NO_SPACE_CONTENT_TRACKING # -- first try to retreive the content associated to this data -- # if proj and data: # content = proj.get_data_property(data, "spaceContent") # -- if content is still none, we can always try to create a new content -- # if content is None and data: # if app: # content = app._create_space_content_0(data) # -- find the space (applet) of the pane or create one if none: space = splittable.getContentAt(paneId) newSpace = False if not space: space = app(proj) newSpace = True elif not space.supports(data): newSpace = True space = app(proj) print "got to space", space, newSpace space.show_data(data) # NO_SPACE_CONTENT_TRACKING # space.add_content(data, content) if newSpace: self.__setSpaceAt(splittable, paneId, space) #################################### # Layout selection related methods # #################################### def __onLayoutListChanged(self, layoutNames): self._layoutMode.blockSignals(True) oldDataMap = {} current = self._layoutMode.currentText() for index in range(self._layoutMode.count()): oldDataMap[str(self._layoutMode.itemText(index))] = self._layoutMode.itemData(index) self._layoutMode.clear() layoutNames.sort() for ln in layoutNames: self._layoutMode.addItem(ln, oldDataMap.get(ln, to_qvariant())) self._layoutMode.adjustSize() ind = self._layoutMode.findText(current) self._layoutMode.setCurrentIndex(ind) self._layoutMode.blockSignals(False) def __onLayoutChosen(self, index): """Called when a user chooses a layout. Fetches the corresponding layout from the registered applications and installs a new splitter in the central window.""" proj = self.__projMan.get_active_project() layoutName = str(self._layoutMode.itemText(index)) if layoutName is None or layoutName == "": return data = self._layoutMode.itemData(index)#.toPyObject() if data and isinstance(data, CustomSplittable): index = self.__centralStack.indexOf(data) if index == -1: self.__centralStack.addWidget(data) self.__centralStack.setCurrentWidget(data) else: # layoutNames encodes the application # name and the layout name: # they are seperated by a period. layout = LayoutManager().get(layoutName) if not layout: return # -- FILL THE LAYOUT WITH WIDGETS DESCRIBED BY THE APPLET MAP -- # create new splittable and retreive objects from previous newSplit, taken = self.__new_splittable(layout.skeleton) contentmap = layout.contentmap afm = AppletFactoryManager() gdm = GlobalDataManager() for paneId in newSplit.leaves(): contentDesc = contentmap.get(paneId) if not contentDesc: space = AppletSpace(proj=proj) else: resName, resType = contentDesc if resType == "g": dataName = resName data = gdm.get_data_by_name(dataName) appFac = DataEditorSelector.mime_type_handler([data.mimetype], applet=True) elif resType == "a": appletName = resName appFac = afm.get(appletName) if appFac is None: self.logger.error("__onLayoutChosen has None factory for "+ resName) continue try: space = appFac(proj) if resType == "g": space.show_data(data) except Exception, e: self.logger.error("__onLayoutChosen cannot display "+ \ resName+":"+\ e.message) traceback.print_exc() continue if space: self.__setSpaceAt(newSplit, paneId, space) self.__centralStack.addWidget(newSplit) self.__centralStack.setCurrentWidget(newSplit) self._layoutMode.setItemData(index, to_qvariant(newSplit))
def getPlaceHolder(self): proj = ProjectManager().get_active_project() return AppletSpace(proj)
class ProjectManagerTreeModel(QtGui.QStandardItemModel): projectRole = QtCore.Qt.UserRole + 1 dataRole = QtCore.Qt.UserRole + 2 def __init__(self, parent=None): QtGui.QStandardItemModel.__init__(self, parent) self.__projMan = ProjectManager() self.__docItemMap = {} self.__activeProjItem = None self.itemChanged.connect(self.__on_item_changed) self.__projMan.active_project_changed.connect(self.set_active_project) self.__activeProj = None activePrj = self.__projMan.get_active_project() if activePrj: self.set_active_project(activePrj) def set_active_project(self, proj, old=None): # -- clear the view (maybe be less radical) -- self.__clear(old) # -- now set active project and reconnect slots to this one -- if proj: self.__activeProj = proj self.__activeProjItem = QtGui.QStandardItem(proj.name) self.__activeProjItem.setData(to_qvariant(proj), self.projectRole) self.appendRow(self.__activeProjItem) self.connect_project(proj) for k, v in proj: self.__on_data_added(proj, v) ##################### # utility functions # ##################### def connect_project(self, proj): if proj: proj.data_added.connect(self.__on_data_added) proj.data_name_changed.connect(self.__on_data_name_changed) proj.project_name_changed.connect(self.__on_active_project_name_changed) proj.modified.connect(self.__on_active_project_modified) proj.saved.connect(self.__on_active_project_saved) proj.closed.connect(self.__on_active_project_saved) def disconnect_project(self, proj): if proj: try_to_disconnect(proj.data_added, self.__on_data_added) try_to_disconnect(proj.data_name_changed, self.__on_data_name_changed) try_to_disconnect(proj.project_name_changed, self.__on_active_project_name_changed) try_to_disconnect(proj.modified, self.__on_active_project_modified) try_to_disconnect(proj.saved, self.__on_active_project_saved) ################### # Protected slots # ################### def __clear(self, proj): self.clear() # -- disconnect previously connected slots -- if proj: self.disconnect_project(proj) def __on_item_changed(self, item): proj = item.data(self.projectRole) doc = item.data(self.dataRole) if proj: proj.name = str(item.text()) else: doc = item.data(self.dataRole) proj = item.parent().data(self.projectRole) if proj and doc: proj.set_data_name(doc, str(item.text())) @muteItemChange def __on_active_project_modified(self, proj): if self.__activeProjItem is None: self.set_active_project(proj) self.__activeProjItem.setText(proj.name+" *") @muteItemChange def __on_active_project_name_changed(self, proj, name): if self.__activeProjItem is None: self.set_active_project(proj) self.__activeProjItem.setText(name+" *") @muteItemChange def __on_active_project_saved(self, proj): if self.__activeProjItem is None: self.set_active_project(proj) self.__activeProjItem.setText(proj.name) @muteItemChange def __on_data_name_changed(self, proj, doc, fixed): docItem = self.__docItemMap.get(doc) if docItem: docItem.setText(fixed) def __on_data_added(self, proj, doc): newItem = QtGui.QStandardItem(doc.name) newItem.setData(to_qvariant(doc), self.dataRole) icon = doc.icon newItem.setIcon(icon) newItem.setDragEnabled(True) parItem = self.__activeProjItem parItem.appendRow(newItem) self.__docItemMap[doc] = newItem ################################ # QStandardItemModel extension # ################################ def mimeTypes(self): return QtGui.QStandardItemModel.mimeTypes(self) + [ProjectManager.mimeformat] def mimeData(self, modelIndexes): if len(modelIndexes) != 1: return None data = QtGui.QStandardItemModel.mimeData(self, modelIndexes) item = self.itemFromIndex(modelIndexes[0]) encoded = QtCore.QByteArray() if item: doc = item.data(self.dataRole) if doc and self.__activeProj: docId = self.__activeProj.get_data_id(doc) encoded = QtCore.QByteArray.number(docId) data.setData(ProjectManager.mimeformat, encoded) return data def headerData(self, section, orientation, role): return to_qvariant()
class ProjectManagerTreeModel(QtGui.QStandardItemModel): projectRole = QtCore.Qt.UserRole + 1 dataRole = QtCore.Qt.UserRole + 2 def __init__(self, parent=None): QtGui.QStandardItemModel.__init__(self, parent) self.__projMan = ProjectManager() self.__docItemMap = {} self.__activeProjItem = None self.itemChanged.connect(self.__on_item_changed) self.__projMan.active_project_changed.connect(self.set_active_project) self.__activeProj = None activePrj = self.__projMan.get_active_project() if activePrj: self.set_active_project(activePrj) def set_active_project(self, proj, old=None): # -- clear the view (maybe be less radical) -- self.__clear(old) # -- now set active project and reconnect slots to this one -- if proj: self.__activeProj = proj self.__activeProjItem = QtGui.QStandardItem(proj.name) self.__activeProjItem.setData(to_qvariant(proj), self.projectRole) self.appendRow(self.__activeProjItem) self.connect_project(proj) for k, v in proj: self.__on_data_added(proj, v) ##################### # utility functions # ##################### def connect_project(self, proj): if proj: proj.data_added.connect(self.__on_data_added) proj.data_name_changed.connect(self.__on_data_name_changed) proj.project_name_changed.connect( self.__on_active_project_name_changed) proj.modified.connect(self.__on_active_project_modified) proj.saved.connect(self.__on_active_project_saved) proj.closed.connect(self.__on_active_project_saved) def disconnect_project(self, proj): if proj: try_to_disconnect(proj.data_added, self.__on_data_added) try_to_disconnect(proj.data_name_changed, self.__on_data_name_changed) try_to_disconnect(proj.project_name_changed, self.__on_active_project_name_changed) try_to_disconnect(proj.modified, self.__on_active_project_modified) try_to_disconnect(proj.saved, self.__on_active_project_saved) ################### # Protected slots # ################### def __clear(self, proj): self.clear() # -- disconnect previously connected slots -- if proj: self.disconnect_project(proj) def __on_item_changed(self, item): proj = item.data(self.projectRole) doc = item.data(self.dataRole) if proj: proj.name = str(item.text()) else: doc = item.data(self.dataRole) proj = item.parent().data(self.projectRole) if proj and doc: proj.set_data_name(doc, str(item.text())) @muteItemChange def __on_active_project_modified(self, proj): if self.__activeProjItem is None: self.set_active_project(proj) self.__activeProjItem.setText(proj.name + " *") @muteItemChange def __on_active_project_name_changed(self, proj, name): if self.__activeProjItem is None: self.set_active_project(proj) self.__activeProjItem.setText(name + " *") @muteItemChange def __on_active_project_saved(self, proj): if self.__activeProjItem is None: self.set_active_project(proj) self.__activeProjItem.setText(proj.name) @muteItemChange def __on_data_name_changed(self, proj, doc, fixed): docItem = self.__docItemMap.get(doc) if docItem: docItem.setText(fixed) def __on_data_added(self, proj, doc): newItem = QtGui.QStandardItem(doc.name) newItem.setData(to_qvariant(doc), self.dataRole) icon = doc.icon newItem.setIcon(icon) newItem.setDragEnabled(True) parItem = self.__activeProjItem parItem.appendRow(newItem) self.__docItemMap[doc] = newItem ################################ # QStandardItemModel extension # ################################ def mimeTypes(self): return QtGui.QStandardItemModel.mimeTypes(self) + [ ProjectManager.mimeformat ] def mimeData(self, modelIndexes): if len(modelIndexes) != 1: return None data = QtGui.QStandardItemModel.mimeData(self, modelIndexes) item = self.itemFromIndex(modelIndexes[0]) encoded = QtCore.QByteArray() if item: doc = item.data(self.dataRole) if doc and self.__activeProj: docId = self.__activeProj.get_data_id(doc) encoded = QtCore.QByteArray.number(docId) data.setData(ProjectManager.mimeformat, encoded) return data def headerData(self, section, orientation, role): return to_qvariant()