def on_buttonDelete_pressed(self): item = self.listProfiles.item(self.listProfiles.currentRow()) profileOldName = item.data(QtCore.Qt.DisplayRole) result = QtGui.QMessageBox.question(self, _("Delete Profile"), _(DELETE_MESSAGE) % profileOldName, buttons = QtGui.QMessageBox.Yes | QtGui.QMessageBox.Ok | QtGui.QMessageBox.Discard, defaultButton = QtGui.QMessageBox.Ok) if result != QtGui.QMessageBox.Discard: PMXProfile.deleteProfile(profileOldName, result == QtGui.QMessageBox.Yes) self.listProfiles.removeItemWidget(item)
def on_buttonDelete_pressed(self): item = self.listProfiles.item(self.listProfiles.currentRow()) profileOldName = item.data(QtCore.Qt.DisplayRole) result = QtGui.QMessageBox.question(self, _("Delete Profile"), _(DELETE_MESSAGE) % profileOldName, buttons=QtGui.QMessageBox.Yes | QtGui.QMessageBox.Ok | QtGui.QMessageBox.Discard, defaultButton=QtGui.QMessageBox.Ok) if result != QtGui.QMessageBox.Discard: PMXProfile.deleteProfile(profileOldName, result == QtGui.QMessageBox.Yes) self.listProfiles.removeItemWidget(item)
def on_buttonCreate_pressed(self): profileName, ok = QtGui.QInputDialog.getText(self, _("Create profile"), _(CREATE_MESSAGE)) while profileName in PMXProfile.PMX_PROFILES.keys(): profileName, ok = QtGui.QInputDialog.getText(self, _("Create profile"), _(CREATE_MESSAGE)) if ok: profileName = PMXProfile.createProfile(profileName) self.listProfiles.addItem(QtGui.QListWidgetItem(QtGui.QIcon.fromTheme("user-identity"), profileName))
def on_buttonRename_pressed(self): profileOldName = self.listProfiles.item(self.listProfiles.currentRow()).data(QtCore.Qt.DisplayRole) profileNewName, ok = QtGui.QInputDialog.getText(self, _("Rename profile"), _(RENAME_MESSAGE) % profileOldName, text=profileOldName) while profileNewName in PMXProfile.PMX_PROFILES.keys(): profileNewName, ok = QtGui.QInputDialog.getText(self, _("Rename profile"), _(RENAME_MESSAGE) % profileOldName, text=profileNewName) if ok: newName = PMXProfile.renameProfile(profileOldName, profileNewName) self.listProfiles.item(self.listProfiles.currentRow()).setData(QtCore.Qt.DisplayRole, newName)
def on_buttonCreate_pressed(self): profileName, ok = QtGui.QInputDialog.getText(self, _("Create profile"), _(CREATE_MESSAGE)) while profileName in PMXProfile.PMX_PROFILES.keys(): profileName, ok = QtGui.QInputDialog.getText( self, _("Create profile"), _(CREATE_MESSAGE)) if ok: profileName = PMXProfile.createProfile(profileName) self.listProfiles.addItem( QtGui.QListWidgetItem(QtGui.QIcon.fromTheme("user-identity"), profileName))
def buildSettings(self, profile): # TODO Cambiar este metodo a buildProfile if profile is None or (profile == "" and not PMXProfile.PMX_PROFILES_DONTASK): #Select profile from prymatex.gui.dialogs.profile import PMXProfileDialog profile = PMXProfileDialog.selectProfile( PMXProfile.PMX_PROFILES_FILE) elif profile == "": #Find default profile in config profile = PMXProfile.PMX_PROFILE_DEFAULT #Settings from prymatex.gui.dialogs.settings import PMXSettingsDialog if not profile: raise ValueError("Invalid Profile") self.profile = PMXProfile(profile) # Configure application self.profile.registerConfigurable(self.__class__) self.profile.configure(self) # TODO Este dialogo no va mas aca self.settingsDialog = PMXSettingsDialog(self)
def on_buttonRename_pressed(self): profileOldName = self.listProfiles.item( self.listProfiles.currentRow()).data(QtCore.Qt.DisplayRole) profileNewName, ok = QtGui.QInputDialog.getText(self, _("Rename profile"), _(RENAME_MESSAGE) % profileOldName, text=profileOldName) while profileNewName in PMXProfile.PMX_PROFILES.keys(): profileNewName, ok = QtGui.QInputDialog.getText( self, _("Rename profile"), _(RENAME_MESSAGE) % profileOldName, text=profileNewName) if ok: newName = PMXProfile.renameProfile(profileOldName, profileNewName) self.listProfiles.item(self.listProfiles.currentRow()).setData( QtCore.Qt.DisplayRole, newName)
def buildSettings(self, profile): # TODO Cambiar este metodo a buildProfile if profile is None or (profile == "" and not PMXProfile.PMX_PROFILES_DONTASK): #Select profile from prymatex.gui.dialogs.profile import PMXProfileDialog profile = PMXProfileDialog.selectProfile(PMXProfile.PMX_PROFILES_FILE) elif profile == "": #Find default profile in config profile = PMXProfile.PMX_PROFILE_DEFAULT #Settings from prymatex.gui.dialogs.settings import PMXSettingsDialog if not profile: raise ValueError("Invalid Profile") self.profile = PMXProfile(profile) # Configure application self.profile.registerConfigurable(self.__class__) self.profile.configure(self) # TODO Este dialogo no va mas aca self.settingsDialog = PMXSettingsDialog(self)
def on_buttonStartPrymatex_pressed(self): PMXProfile.PMX_PROFILE_DEFAULT = self.listProfiles.item(self.listProfiles.currentRow()).data(QtCore.Qt.DisplayRole) PMXProfile.saveProfiles() self.accept()
def on_checkDontAsk_clicked(self): PMXProfile.PMX_PROFILES_DONTASK = self.checkDontAsk.isChecked() PMXProfile.saveProfiles()
def on_buttonStartPrymatex_pressed(self): PMXProfile.PMX_PROFILE_DEFAULT = self.listProfiles.item( self.listProfiles.currentRow()).data(QtCore.Qt.DisplayRole) PMXProfile.saveProfiles() self.accept()
class PMXApplication(QtGui.QApplication): """The application instance. There can't be two apps running simultaneously, since configuration issues may occur. The application loads the PMX Support.""" #======================================================================= # Settings #======================================================================= SETTINGS_GROUP = "Global" @pmxConfigPorperty(default=resources.APPLICATION_STYLE) def styleSheet(self, style): self.setStyleSheet(style) askAboutExternalActions = pmxConfigPorperty(default=False) RESTART_CODE = 1000 def __init__(self): """Inicialización de la aplicación.""" #TODO: Pasar los argumentos a la QApplication QtGui.QApplication.__init__(self, []) # Some init's self.setApplicationName(prymatex.__name__.title()) self.setApplicationVersion(prymatex.__version__) self.setOrganizationDomain(prymatex.__url__) self.setOrganizationName(prymatex.__author__) self.platform = sys.platform resources.loadPrymatexResources(PMXProfile.PMX_SHARE_PATH) #Connects self.aboutToQuit.connect(self.closePrymatex) def installTranslator(self): pass #slanguage = QtCore.QLocale.system().name() #print language #self.translator = QtCore.QTranslator() #print os.path.join(PMXProfile.PMX_SHARE_PATH, "Languages") #self.translator.load(settings.LANGUAGE) #self.installTranslator(translator) def buildSplashScreen(self): from prymatex.widgets.splash import SplashScreen splash_image = resources.getImage('newsplash') splash = SplashScreen(splash_image) splash.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.SplashScreen) splashFont = QtGui.QFont("Monospace", 11) splashFont.setStyleStrategy(QtGui.QFont.PreferAntialias) splash.setFont(splashFont) splash.setMask(splash_image.mask()) return splash def loadGraphicalUserInterface(self): splash = self.buildSplashScreen() splash.show() try: self.cacheManager = self.setupCacheManager() #Cache system Manager self.pluginManager = self.setupPluginManager( ) #Prepare plugin manager #TODO: Cambiar los setup por build, que retornen los manager # Loads self.supportManager = self.setupSupportManager() #Support Manager self.fileManager = self.setupFileManager() #File Manager self.projectManager = self.setupProjectManager() #Project Manager self.kernelManager = self.setupKernelManager( ) #Console kernel Manager self.setupCoroutines() self.setupZeroMQContext() self.setupMainWindow() self.setupServer() # Setup Dialogs self.setupDialogs() #Connect all loads self.projectManager.loadProjects() self.supportManager.loadSupport(splash.showMessage) self.settingsDialog.loadSettings() # Creates the Main Window self.createMainWindow() splash.finish(self.mainWindow) except KeyboardInterrupt: self.logger.critical( "\nQuit signal catched during application startup. Quiting...") self.quit() def unloadGraphicalUserInterface(self): #TODO: ver como dejar todo lindo y ordenado para terminar correctamente #if self.zmqContext is not None: # self.zmqContext.destroy() self.mainWindow.close() del self.mainWindow def resetSettings(self): self.profile.clear() def switchProfile(self): from prymatex.gui.dialogs.profile import PMXProfileDialog profile = PMXProfileDialog.switchProfile(PMXProfile.PMX_PROFILES_FILE) if profile is not None and profile != self.profile.PMX_PROFILE_NAME: self.restart() def restart(self): self.exit(self.RESTART_CODE) def buildSettings(self, profile): # TODO Cambiar este metodo a buildProfile if profile is None or (profile == "" and not PMXProfile.PMX_PROFILES_DONTASK): #Select profile from prymatex.gui.dialogs.profile import PMXProfileDialog profile = PMXProfileDialog.selectProfile( PMXProfile.PMX_PROFILES_FILE) elif profile == "": #Find default profile in config profile = PMXProfile.PMX_PROFILE_DEFAULT #Settings from prymatex.gui.dialogs.settings import PMXSettingsDialog if not profile: raise ValueError("Invalid Profile") self.profile = PMXProfile(profile) # Configure application self.profile.registerConfigurable(self.__class__) self.profile.configure(self) # TODO Este dialogo no va mas aca self.settingsDialog = PMXSettingsDialog(self) def checkSingleInstance(self): """ Checks if there's another instance using current profile """ self.fileLock = os.path.join(self.profile.PMX_PROFILE_PATH, 'prymatex.pid') if os.path.exists(self.fileLock): #Mejorar esto pass #raise exceptions.AlreadyRunningError('%s seems to be runnig. Please close the instance or run other profile.' % (self.profile.PMX_PROFILE_NAME)) else: f = open(self.fileLock, 'w') f.write('%s' % self.applicationPid()) f.close() #======================================================== # Logging system and loggers #======================================================== def getLogger(self, name): """ return logger, for filter by name in future """ return logging.getLogger(name) def setupLogging(self, verbose, namePattern): from datetime import datetime level = [ logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG ][verbose % 5] # File name filename = os.path.join( self.profile.PMX_LOG_PATH, '%s-%s.log' % (logging.getLevelName(level), datetime.now().strftime('%d-%m-%Y'))) logging.basicConfig(filename=filename, level=level) # Console handler ch = logging.StreamHandler() formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') ch.setFormatter(formatter) ch.setLevel(level) if namePattern: #Solo al de consola ch.addFilter(NameFilter(namePattern)) logging.root.addHandler(ch) logging.root.info("Application startup") logging.root.debug("Application startup debug") self.logger = logging.root # Route Qt output Qt.qInstallMsgHandler(self.qtMessageHandler) def qtMessageHandler(self, msgType, msgString): ''' Route Qt messaging system into Prymatex/Python one''' if msgType == Qt.QtDebugMsg: self.logger.debug(msgString) elif msgType == Qt.QtWarningMsg: self.logger.warn(msgString) elif msgType == Qt.QtCriticalMsg: self.logger.critical(msgString) elif msgType == Qt.QtFatalMsg: self.logger.fatal(msgString) elif msgType == Qt.QtSystemMsg: self.logger.debug("System: %s" % msgString) #======================================================== # Managers #======================================================== @logtime def setupSupportManager(self): from prymatex.managers.support import SupportManager self.populateComponent(SupportManager) manager = SupportManager(self) self.profile.configure(manager) #Prepare prymatex namespace sharePath = self.profile.value('PMX_SHARE_PATH') manager.addNamespace('prymatex', sharePath) manager.updateEnvironment({ #TextMate Compatible :P 'TM_APP_PATH': self.profile.value('PMX_APP_PATH'), 'TM_SUPPORT_PATH': manager.environment['PMX_SUPPORT_PATH'], 'TM_BUNDLES_PATH': manager.environment['PMX_BUNDLES_PATH'], 'TM_THEMES_PATH': manager.environment['PMX_THEMES_PATH'], 'TM_PID': self.applicationPid(), #Prymatex 'PMX_APP_NAME': self.applicationName().title(), 'PMX_APP_PATH': self.profile.value('PMX_APP_PATH'), 'PMX_PREFERENCES_PATH': self.profile.value('PMX_PREFERENCES_PATH'), 'PMX_VERSION': self.applicationVersion(), 'PMX_PID': self.applicationPid() }) #Prepare user namespace homePath = self.profile.value('PMX_HOME_PATH') manager.addNamespace('user', homePath) manager.updateEnvironment({ 'PMX_HOME_PATH': homePath, 'PMX_PROFILE_PATH': self.profile.value('PMX_PROFILE_PATH'), 'PMX_TMP_PATH': self.profile.value('PMX_TMP_PATH'), 'PMX_LOG_PATH': self.profile.value('PMX_LOG_PATH') }) return manager def setupFileManager(self): from prymatex.managers.files import FileManager self.populateComponent(FileManager) manager = FileManager(self) self.profile.configure(manager) manager.filesytemChange.connect(self.on_filesytemChange) return manager def setupProjectManager(self): from prymatex.managers.projects import ProjectManager self.populateComponent(ProjectManager) manager = ProjectManager(self) self.profile.configure(manager) return manager def setupKernelManager(self): kernelManager = None try: from IPython.frontend.qt.kernelmanager import QtKernelManager kernelManager = QtKernelManager() kernelManager.start_kernel() kernelManager.start_channels() if hasattr(kernelManager, "connection_file"): ipconnection = kernelManager.connection_file else: shell_port = kernelManager.shell_address[1] iopub_port = kernelManager.sub_address[1] stdin_port = kernelManager.stdin_address[1] hb_port = kernelManager.hb_address[1] ipconnection = "--shell={0} --iopub={1} --stdin={2} --hb={3}".format( shell_port, iopub_port, stdin_port, hb_port) self.supportManager.updateEnvironment( {"PMX_IPYTHON_CONNECTION": ipconnection}) except ImportError as e: self.logger.warn("Warning: %s" % e) kernelManager = None return kernelManager def setupCacheManager(self): from prymatex.managers.cache import CacheManager return CacheManager() def setupPluginManager(self): from prymatex.managers.plugins import PluginManager self.populateComponent(PluginManager) pluginManager = PluginManager(self) self.profile.configure(pluginManager) # TODO: Ruta de los plugins ver de aprovechar settings quiza esta sea una ruta base solamente pluginManager.addPluginDirectory( self.profile.value('PMX_PLUGINS_PATH')) pluginManager.loadPlugins() return pluginManager def setupCoroutines(self): self.scheduler = coroutines.Scheduler(self) def setupZeroMQContext(self): try: from prymatex.utils import zeromqt self.zmqContext = zeromqt.ZeroMQTContext(parent=self) except ImportError as e: self.logger.warn("Warning: %s" % e) self.zmqContext = None def setupMainWindow(self): from prymatex.gui.mainwindow import PMXMainWindow self.populateComponent(PMXMainWindow) def setupServer(self): #Seria mejor que esto no falle pero bueno tengo que preguntar por none if self.zmqContext is not None: from prymatex.core.server import PrymatexServer self.populateComponent(PrymatexServer) self.server = PrymatexServer(self) #======================================================== # Dialogs #======================================================== def setupDialogs(self): # TODO: Creo que esto del bundle editor global asi no va a caminar muy bien #Bundle Editor from prymatex.gui.support.bundleeditor import PMXBundleEditor self.populateComponent(PMXBundleEditor) self.bundleEditor = PMXBundleEditor(self) #self.bundleEditor.setModal(True) def closePrymatex(self): self.logger.debug("Close") self.profile.saveState(self.mainWindow) os.unlink(self.fileLock) def commitData(self, manager): print "Commit data" def saveState(self, manager): print "saveState" pass #======================================================== # Components #======================================================== def extendComponent(self, componentClass): componentClass.application = self componentClass.logger = self.getLogger('.'.join( [componentClass.__module__, componentClass.__name__])) def populateComponent(self, componentClass): self.extendComponent(componentClass) self.profile.registerConfigurable(componentClass) for settingClass in componentClass.contributeToSettings(): try: self.extendComponent(settingClass) self.settingsDialog.register( settingClass(componentClass.settings)) except (RuntimeError, ImportError): # TODO: Inform user but dont' prevent pmx from starting pass def createWidgetInstance(self, widgetClass, parent): # TODO Que parent sea opcional y pueda ser la mainWindow si no viene seteado return self.pluginManager.createWidgetInstance(widgetClass, parent) #======================================================== # Create Zmq Sockets #======================================================== def zmqSocket(self, socketType, name, interface='tcp://127.0.0.1'): # TODO ver la variable aca socket = self.zmqContext.socket(socketType) port = socket.bind_to_random_port(interface) self.supportManager.addToEnvironment("PMX_" + name.upper() + "_PORT", port) return socket #======================================================== # Editors and mainWindow handle #======================================================== def createEditorInstance(self, filePath=None, parent=None): editorClass = filePath is not None and self.pluginManager.findEditorClassForFile( filePath) or self.pluginManager.defaultEditor() if editorClass is not None: return self.createWidgetInstance(editorClass, parent) def createMainWindow(self): """Creates the windows""" from prymatex.gui.mainwindow import PMXMainWindow #TODO: Testeame con mas de una for _ in range(1): self.mainWindow = PMXMainWindow(self) #Configure and add dockers self.pluginManager.populateMainWindow(self.mainWindow) self.profile.configure(self.mainWindow) self.mainWindow.show() self.profile.restoreState(self.mainWindow) if not self.mainWindow.editors(): self.mainWindow.addEmptyEditor() def showMessage(self, message): #Si tengo mainwindow vamos por este camino, sino hacerlo llegar de otra forma self.mainWindow.showMessage(message) def currentEditor(self): return self.mainWindow.currentEditor() def findEditorForFile(self, filePath): #Para cada mainwindow buscar el editor return self.mainWindow, self.mainWindow.findEditorForFile(filePath) def canBeHandled(self, filePath): #from prymatex.utils.pyqtdebug import ipdb_set_trace #ipdb_set_trace() ext = os.path.splitext(filePath)[1].replace('.', '') for fileTypes in [ syntax.item.fileTypes for syntax in self.supportManager.getAllSyntaxes() if hasattr(syntax.item, 'fileTypes') and syntax.item.fileTypes ]: if ext in fileTypes: return True return False def openFile(self, filePath, cursorPosition=None, focus=True, mainWindow=None, useTasks=True): """Open a editor in current window""" filePath = self.fileManager.normcase(filePath) if self.fileManager.isOpen(filePath): mainWindow, editor = self.findEditorForFile(filePath) if editor is not None: mainWindow.setCurrentEditor(editor) if isinstance(cursorPosition, tuple): editor.setCursorPosition(cursorPosition) elif self.fileManager.exists(filePath): mainWindow = mainWindow or self.mainWindow editor = self.createEditorInstance(filePath, mainWindow) def on_editorReady(mainWindow, editor, cursorPosition, focus): def editorReady(openResult): if isinstance(cursorPosition, tuple): editor.setCursorPosition(cursorPosition) mainWindow.tryCloseEmptyEditor() mainWindow.addEditor(editor, focus) return editorReady if useTasks and inspect.isgeneratorfunction(editor.open): task = self.scheduler.newTask(editor.open(filePath)) task.done.connect( on_editorReady(mainWindow, editor, cursorPosition, focus)) elif inspect.isgeneratorfunction(editor.open): on_editorReady(mainWindow, editor, cursorPosition, focus)(list(editor.open(filePath))) else: on_editorReady(mainWindow, editor, cursorPosition, focus)(editor.open(filePath)) def openDirectory(self, directoryPath): raise NotImplementedError( "Directory contents should be opened as files here") def handleUrlCommand(self, url): if isinstance(url, basestring): url = QtCore.QUrl(url) if url.scheme() == "txmt": #TODO: Controlar que sea un open sourceFile = url.queryItemValue('url') position = (0, 0) line = url.queryItemValue('line') if line: position = (int(line) - 1, position[1]) column = url.queryItemValue('column') if column: position = (position[0], int(column) - 1) if sourceFile: filePath = QtCore.QUrl(sourceFile, QtCore.QUrl.TolerantMode).toLocalFile() self.openFile(filePath, position) else: self.currentEditor().setCursorPosition(position) def openArgumentFiles(self, args): for filePath in filter(lambda f: os.path.exists(f), args): if os.path.isfile(filePath): self.openFile(filePath) else: self.openDirectory(filePath) def checkExternalAction(self, mainWindow, editor): if editor.isExternalChanged(): message = "The file '%s' has been changed on the file system, Do you want to replace the editor contents with these changes?" result = QtGui.QMessageBox.question( editor, _("File changed"), _(message) % editor.filePath, buttons=QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, defaultButton=QtGui.QMessageBox.Yes ) if self.askAboutExternalActions else QtGui.QMessageBox.Yes if result == QtGui.QMessageBox.Yes: if inspect.isgeneratorfunction(editor.reload): task = self.scheduler.newTask(editor.reload()) else: editor.reload() elif result == QtGui.QMessageBox.No: pass elif editor.isExternalDeleted(): message = "The file '%s' has been deleted or is not accessible. Do you want to save your changes or close the editor without saving?" result = QtGui.QMessageBox.question( editor, _("File deleted"), _(message) % editor.filePath, buttons=QtGui.QMessageBox.Save | QtGui.QMessageBox.Close, defaultButton=QtGui.QMessageBox.Close ) if self.askAboutExternalActions else QtGui.QMessageBox.Close if result == QtGui.QMessageBox.Close: mainWindow.closeEditor(editor) elif result == QtGui.QMessageBox.Save: mainWindow.saveEditor(editor) def on_filesytemChange(self, filePath, change): mainWindow, editor = self.findEditorForFile(filePath) editor.setExternalAction(change) if mainWindow.currentEditor() == editor: self.checkExternalAction(mainWindow, editor) #--------------------------------------------------- # Exceptions, Print exceptions in a window #--------------------------------------------------- def replaceSysExceptHook(self): def displayExceptionDialog(exctype, value, traceback): ''' Display a nice dialog showing the python traceback''' from prymatex.gui.emergency.tracedialog import PMXTraceBackDialog sys.__excepthook__(exctype, value, traceback) PMXTraceBackDialog.fromSysExceptHook(exctype, value, traceback).exec_() sys.excepthook = displayExceptionDialog def __str__(self): return '<PMXApplication at {} PID: {}>'.format(hash(self), os.getpid()) __unicode__ = __repr__ = __str__
class PMXApplication(QtGui.QApplication): """The application instance. There can't be two apps running simultaneously, since configuration issues may occur. The application loads the PMX Support.""" #======================================================================= # Settings #======================================================================= SETTINGS_GROUP = "Global" @pmxConfigPorperty(default = resources.APPLICATION_STYLE) def styleSheet(self, style): self.setStyleSheet(style) askAboutExternalActions = pmxConfigPorperty(default = False) RESTART_CODE = 1000 def __init__(self): """Inicialización de la aplicación.""" #TODO: Pasar los argumentos a la QApplication QtGui.QApplication.__init__(self, []) # Some init's self.setApplicationName(prymatex.__name__.title()) self.setApplicationVersion(prymatex.__version__) self.setOrganizationDomain(prymatex.__url__) self.setOrganizationName(prymatex.__author__) self.platform = sys.platform resources.loadPrymatexResources(PMXProfile.PMX_SHARE_PATH) #Connects self.aboutToQuit.connect(self.closePrymatex) def installTranslator(self): pass #slanguage = QtCore.QLocale.system().name() #print language #self.translator = QtCore.QTranslator() #print os.path.join(PMXProfile.PMX_SHARE_PATH, "Languages") #self.translator.load(settings.LANGUAGE) #self.installTranslator(translator) def buildSplashScreen(self): from prymatex.widgets.splash import SplashScreen splash_image = resources.getImage('newsplash') splash = SplashScreen(splash_image) splash.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.SplashScreen) splashFont = QtGui.QFont("Monospace", 11) splashFont.setStyleStrategy(QtGui.QFont.PreferAntialias) splash.setFont(splashFont) splash.setMask(splash_image.mask()) return splash def loadGraphicalUserInterface(self): splash = self.buildSplashScreen() splash.show() try: self.cacheManager = self.setupCacheManager() #Cache system Manager self.pluginManager = self.setupPluginManager() #Prepare plugin manager #TODO: Cambiar los setup por build, que retornen los manager # Loads self.supportManager = self.setupSupportManager() #Support Manager self.fileManager = self.setupFileManager() #File Manager self.projectManager = self.setupProjectManager() #Project Manager self.kernelManager = self.setupKernelManager() #Console kernel Manager self.setupCoroutines() self.setupZeroMQContext() self.setupMainWindow() self.setupServer() # Setup Dialogs self.setupDialogs() #Connect all loads self.projectManager.loadProjects() self.supportManager.loadSupport(splash.showMessage) self.settingsDialog.loadSettings() # Creates the Main Window self.createMainWindow() splash.finish(self.mainWindow) except KeyboardInterrupt: self.logger.critical("\nQuit signal catched during application startup. Quiting...") self.quit() def unloadGraphicalUserInterface(self): #TODO: ver como dejar todo lindo y ordenado para terminar correctamente #if self.zmqContext is not None: # self.zmqContext.destroy() self.mainWindow.close() del self.mainWindow def resetSettings(self): self.profile.clear() def switchProfile(self): from prymatex.gui.dialogs.profile import PMXProfileDialog profile = PMXProfileDialog.switchProfile(PMXProfile.PMX_PROFILES_FILE) if profile is not None and profile != self.profile.PMX_PROFILE_NAME: self.restart() def restart(self): self.exit(self.RESTART_CODE) def buildSettings(self, profile): # TODO Cambiar este metodo a buildProfile if profile is None or (profile == "" and not PMXProfile.PMX_PROFILES_DONTASK): #Select profile from prymatex.gui.dialogs.profile import PMXProfileDialog profile = PMXProfileDialog.selectProfile(PMXProfile.PMX_PROFILES_FILE) elif profile == "": #Find default profile in config profile = PMXProfile.PMX_PROFILE_DEFAULT #Settings from prymatex.gui.dialogs.settings import PMXSettingsDialog if not profile: raise ValueError("Invalid Profile") self.profile = PMXProfile(profile) # Configure application self.profile.registerConfigurable(self.__class__) self.profile.configure(self) # TODO Este dialogo no va mas aca self.settingsDialog = PMXSettingsDialog(self) def checkSingleInstance(self): """ Checks if there's another instance using current profile """ self.fileLock = os.path.join(self.profile.PMX_PROFILE_PATH, 'prymatex.pid') if os.path.exists(self.fileLock): #Mejorar esto pass #raise exceptions.AlreadyRunningError('%s seems to be runnig. Please close the instance or run other profile.' % (self.profile.PMX_PROFILE_NAME)) else: f = open(self.fileLock, 'w') f.write('%s' % self.applicationPid()) f.close() #======================================================== # Logging system and loggers #======================================================== def getLogger(self, name): """ return logger, for filter by name in future """ return logging.getLogger(name) def setupLogging(self, verbose, namePattern): from datetime import datetime level = [ logging.CRITICAL, logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG ][verbose % 5] # File name filename = os.path.join(self.profile.PMX_LOG_PATH, '%s-%s.log' % (logging.getLevelName(level), datetime.now().strftime('%d-%m-%Y'))) logging.basicConfig(filename=filename, level=level) # Console handler ch = logging.StreamHandler() formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') ch.setFormatter(formatter) ch.setLevel(level) if namePattern: #Solo al de consola ch.addFilter(NameFilter(namePattern)) logging.root.addHandler(ch) logging.root.info("Application startup") logging.root.debug("Application startup debug") self.logger = logging.root # Route Qt output Qt.qInstallMsgHandler(self.qtMessageHandler) def qtMessageHandler(self, msgType, msgString): ''' Route Qt messaging system into Prymatex/Python one''' if msgType == Qt.QtDebugMsg: self.logger.debug(msgString) elif msgType == Qt.QtWarningMsg: self.logger.warn(msgString) elif msgType == Qt.QtCriticalMsg: self.logger.critical(msgString) elif msgType == Qt.QtFatalMsg: self.logger.fatal(msgString) elif msgType == Qt.QtSystemMsg: self.logger.debug("System: %s" % msgString) #======================================================== # Managers #======================================================== @logtime def setupSupportManager(self): from prymatex.managers.support import SupportManager self.populateComponent(SupportManager) manager = SupportManager(self) self.profile.configure(manager) #Prepare prymatex namespace sharePath = self.profile.value('PMX_SHARE_PATH') manager.addNamespace('prymatex', sharePath) manager.updateEnvironment({ #TextMate Compatible :P 'TM_APP_PATH': self.profile.value('PMX_APP_PATH'), 'TM_SUPPORT_PATH': manager.environment['PMX_SUPPORT_PATH'], 'TM_BUNDLES_PATH': manager.environment['PMX_BUNDLES_PATH'], 'TM_THEMES_PATH': manager.environment['PMX_THEMES_PATH'], 'TM_PID': self.applicationPid(), #Prymatex 'PMX_APP_NAME': self.applicationName().title(), 'PMX_APP_PATH': self.profile.value('PMX_APP_PATH'), 'PMX_PREFERENCES_PATH': self.profile.value('PMX_PREFERENCES_PATH'), 'PMX_VERSION': self.applicationVersion(), 'PMX_PID': self.applicationPid() }) #Prepare user namespace homePath = self.profile.value('PMX_HOME_PATH') manager.addNamespace('user', homePath) manager.updateEnvironment({ 'PMX_HOME_PATH': homePath, 'PMX_PROFILE_PATH': self.profile.value('PMX_PROFILE_PATH'), 'PMX_TMP_PATH': self.profile.value('PMX_TMP_PATH'), 'PMX_LOG_PATH': self.profile.value('PMX_LOG_PATH') }) return manager def setupFileManager(self): from prymatex.managers.files import FileManager self.populateComponent(FileManager) manager = FileManager(self) self.profile.configure(manager) manager.filesytemChange.connect(self.on_filesytemChange) return manager def setupProjectManager(self): from prymatex.managers.projects import ProjectManager self.populateComponent(ProjectManager) manager = ProjectManager(self) self.profile.configure(manager) return manager def setupKernelManager(self): kernelManager = None try: from IPython.frontend.qt.kernelmanager import QtKernelManager kernelManager = QtKernelManager() kernelManager.start_kernel() kernelManager.start_channels() if hasattr(kernelManager, "connection_file"): ipconnection = kernelManager.connection_file else: shell_port = kernelManager.shell_address[1] iopub_port = kernelManager.sub_address[1] stdin_port = kernelManager.stdin_address[1] hb_port = kernelManager.hb_address[1] ipconnection = "--shell={0} --iopub={1} --stdin={2} --hb={3}".format(shell_port, iopub_port, stdin_port, hb_port) self.supportManager.updateEnvironment({ "PMX_IPYTHON_CONNECTION": ipconnection }) except ImportError as e: self.logger.warn("Warning: %s" % e) kernelManager = None return kernelManager def setupCacheManager(self): from prymatex.managers.cache import CacheManager return CacheManager() def setupPluginManager(self): from prymatex.managers.plugins import PluginManager self.populateComponent(PluginManager) pluginManager = PluginManager(self) self.profile.configure(pluginManager) # TODO: Ruta de los plugins ver de aprovechar settings quiza esta sea una ruta base solamente pluginManager.addPluginDirectory(self.profile.value('PMX_PLUGINS_PATH')) pluginManager.loadPlugins() return pluginManager def setupCoroutines(self): self.scheduler = coroutines.Scheduler(self) def setupZeroMQContext(self): try: from prymatex.utils import zeromqt self.zmqContext = zeromqt.ZeroMQTContext(parent = self) except ImportError as e: self.logger.warn("Warning: %s" % e) self.zmqContext = None def setupMainWindow(self): from prymatex.gui.mainwindow import PMXMainWindow self.populateComponent(PMXMainWindow) def setupServer(self): #Seria mejor que esto no falle pero bueno tengo que preguntar por none if self.zmqContext is not None: from prymatex.core.server import PrymatexServer self.populateComponent(PrymatexServer) self.server = PrymatexServer(self) #======================================================== # Dialogs #======================================================== def setupDialogs(self): # TODO: Creo que esto del bundle editor global asi no va a caminar muy bien #Bundle Editor from prymatex.gui.support.bundleeditor import PMXBundleEditor self.populateComponent(PMXBundleEditor) self.bundleEditor = PMXBundleEditor(self) #self.bundleEditor.setModal(True) def closePrymatex(self): self.logger.debug("Close") self.profile.saveState(self.mainWindow) os.unlink(self.fileLock) def commitData(self, manager): print "Commit data" def saveState(self, manager): print "saveState" pass #======================================================== # Components #======================================================== def extendComponent(self, componentClass): componentClass.application = self componentClass.logger = self.getLogger('.'.join([componentClass.__module__, componentClass.__name__])) def populateComponent(self, componentClass): self.extendComponent(componentClass) self.profile.registerConfigurable(componentClass) for settingClass in componentClass.contributeToSettings(): try: self.extendComponent(settingClass) self.settingsDialog.register(settingClass(componentClass.settings)) except (RuntimeError, ImportError): # TODO: Inform user but dont' prevent pmx from starting pass def createWidgetInstance(self, widgetClass, parent): # TODO Que parent sea opcional y pueda ser la mainWindow si no viene seteado return self.pluginManager.createWidgetInstance(widgetClass, parent) #======================================================== # Create Zmq Sockets #======================================================== def zmqSocket(self, socketType, name, interface='tcp://127.0.0.1'): # TODO ver la variable aca socket = self.zmqContext.socket(socketType) port = socket.bind_to_random_port(interface) self.supportManager.addToEnvironment("PMX_" + name.upper() + "_PORT", port) return socket #======================================================== # Editors and mainWindow handle #======================================================== def createEditorInstance(self, filePath = None, parent = None): editorClass = filePath is not None and self.pluginManager.findEditorClassForFile(filePath) or self.pluginManager.defaultEditor() if editorClass is not None: return self.createWidgetInstance(editorClass, parent) def createMainWindow(self): """Creates the windows""" from prymatex.gui.mainwindow import PMXMainWindow #TODO: Testeame con mas de una for _ in range(1): self.mainWindow = PMXMainWindow(self) #Configure and add dockers self.pluginManager.populateMainWindow(self.mainWindow) self.profile.configure(self.mainWindow) self.mainWindow.show() self.profile.restoreState(self.mainWindow) if not self.mainWindow.editors(): self.mainWindow.addEmptyEditor() def showMessage(self, message): #Si tengo mainwindow vamos por este camino, sino hacerlo llegar de otra forma self.mainWindow.showMessage(message) def currentEditor(self): return self.mainWindow.currentEditor() def findEditorForFile(self, filePath): #Para cada mainwindow buscar el editor return self.mainWindow, self.mainWindow.findEditorForFile(filePath) def canBeHandled(self, filePath): #from prymatex.utils.pyqtdebug import ipdb_set_trace #ipdb_set_trace() ext = os.path.splitext(filePath)[1].replace('.', '') for fileTypes in [ syntax.item.fileTypes for syntax in self.supportManager.getAllSyntaxes() if hasattr(syntax.item, 'fileTypes') and syntax.item.fileTypes ]: if ext in fileTypes: return True return False def openFile(self, filePath, cursorPosition = None, focus = True, mainWindow = None, useTasks = True): """Open a editor in current window""" filePath = self.fileManager.normcase(filePath) if self.fileManager.isOpen(filePath): mainWindow, editor = self.findEditorForFile(filePath) if editor is not None: mainWindow.setCurrentEditor(editor) if isinstance(cursorPosition, tuple): editor.setCursorPosition(cursorPosition) elif self.fileManager.exists(filePath): mainWindow = mainWindow or self.mainWindow editor = self.createEditorInstance(filePath, mainWindow) def on_editorReady(mainWindow, editor, cursorPosition, focus): def editorReady(openResult): if isinstance(cursorPosition, tuple): editor.setCursorPosition(cursorPosition) mainWindow.tryCloseEmptyEditor() mainWindow.addEditor(editor, focus) return editorReady if useTasks and inspect.isgeneratorfunction(editor.open): task = self.scheduler.newTask( editor.open(filePath) ) task.done.connect( on_editorReady(mainWindow, editor, cursorPosition, focus) ) elif inspect.isgeneratorfunction(editor.open): on_editorReady(mainWindow, editor, cursorPosition, focus)(list(editor.open(filePath))) else: on_editorReady(mainWindow, editor, cursorPosition, focus)(editor.open(filePath)) def openDirectory(self, directoryPath): raise NotImplementedError("Directory contents should be opened as files here") def handleUrlCommand(self, url): if isinstance(url, basestring): url = QtCore.QUrl(url) if url.scheme() == "txmt": #TODO: Controlar que sea un open sourceFile = url.queryItemValue('url') position = (0, 0) line = url.queryItemValue('line') if line: position = (int(line) - 1, position[1]) column = url.queryItemValue('column') if column: position = (position[0], int(column) - 1) if sourceFile: filePath = QtCore.QUrl(sourceFile, QtCore.QUrl.TolerantMode).toLocalFile() self.openFile(filePath, position) else: self.currentEditor().setCursorPosition(position) def openArgumentFiles(self, args): for filePath in filter(lambda f: os.path.exists(f), args): if os.path.isfile(filePath): self.openFile(filePath) else: self.openDirectory(filePath) def checkExternalAction(self, mainWindow, editor): if editor.isExternalChanged(): message = "The file '%s' has been changed on the file system, Do you want to replace the editor contents with these changes?" result = QtGui.QMessageBox.question(editor, _("File changed"), _(message) % editor.filePath, buttons = QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, defaultButton = QtGui.QMessageBox.Yes) if self.askAboutExternalActions else QtGui.QMessageBox.Yes if result == QtGui.QMessageBox.Yes: if inspect.isgeneratorfunction(editor.reload): task = self.scheduler.newTask( editor.reload() ) else: editor.reload() elif result == QtGui.QMessageBox.No: pass elif editor.isExternalDeleted(): message = "The file '%s' has been deleted or is not accessible. Do you want to save your changes or close the editor without saving?" result = QtGui.QMessageBox.question(editor, _("File deleted"), _(message) % editor.filePath, buttons = QtGui.QMessageBox.Save | QtGui.QMessageBox.Close, defaultButton = QtGui.QMessageBox.Close) if self.askAboutExternalActions else QtGui.QMessageBox.Close if result == QtGui.QMessageBox.Close: mainWindow.closeEditor(editor) elif result == QtGui.QMessageBox.Save: mainWindow.saveEditor(editor) def on_filesytemChange(self, filePath, change): mainWindow, editor = self.findEditorForFile(filePath) editor.setExternalAction(change) if mainWindow.currentEditor() == editor: self.checkExternalAction(mainWindow, editor) #--------------------------------------------------- # Exceptions, Print exceptions in a window #--------------------------------------------------- def replaceSysExceptHook(self): def displayExceptionDialog(exctype, value, traceback): ''' Display a nice dialog showing the python traceback''' from prymatex.gui.emergency.tracedialog import PMXTraceBackDialog sys.__excepthook__(exctype, value, traceback) PMXTraceBackDialog.fromSysExceptHook(exctype, value, traceback).exec_() sys.excepthook = displayExceptionDialog def __str__(self): return '<PMXApplication at {} PID: {}>'.format(hash(self), os.getpid()) __unicode__ = __repr__ = __str__