Ejemplo n.º 1
0
def main():
    global win
    signal.signal(signal.SIGINT, exit)
    args = parse_arguments()
    appKey = "scudcloud.pid"
    socket = QLocalSocket()
    socket.connectToServer(appKey)
    if socket.isOpen():
        socket.close()
        socket.deleteLater()
        return 0
    socket.deleteLater()
    app = QtGui.QApplication(sys.argv)
    app.setApplicationName(Resources.APP_NAME)
    app.setWindowIcon(QtGui.QIcon(Resources.get_path('scudcloud.png')))

    try:
        settings_path = load_settings(args.confdir)
    except:
        print("Configuration directory " + args.confdir +\
              " could not be created! Exiting...")
        raise SystemExit()
    minimized = True if args.minimized is True else None

    win = sca.ScudCloud(debug=args.debug, minimized=minimized, settings_path=settings_path)
    app.commitDataRequest.connect(win.setForceClose, type=QtCore.Qt.DirectConnection)

    server = QLocalServer()
    server.newConnection.connect(restore)
    server.listen(appKey)
    win.restore()
    if win.minimized is None:
        win.show()
    sys.exit(app.exec_())
Ejemplo n.º 2
0
def init():
    """Start listening to incoming connections."""
    global _server
    if _server is not None:
        return

    server = QLocalServer(None)

    # find a free socket name to use
    for name in ids():
        if server.listen(name):
            break
    else:
        # all names failed, try to contact and remove stale file if that fails
        socket = QLocalSocket()
        for name in ids():
            socket.connectToServer(name)
            if not socket.waitForConnected(10000):
                QLocalServer.removeServer(name)
                if server.listen(name):
                    break
            else:
                socket.disconnectFromServer()
        else:
            # no ids left, don't listen
            return
    app.aboutToQuit.connect(server.close)
    server.newConnection.connect(slot_new_connection)
    os.environ["FRESCOBALDI_SOCKET"] = name
    _server = server
Ejemplo n.º 3
0
def testSingleInstanceOrExit():
    connected = False
    #try connect to QLocalServer
    local_sock = QLocalSocket()
    import sys
    QObject.connect(local_sock, SIGNAL('connected()'), sys.exit)
    connected = local_sock.connectToServer(qApp.applicationName())
    global LOCALSERVER
    if not connected:
        LOCALSERVER = QLocalServer()
        print 'setting up localserver', qApp.applicationName()
        ret = LOCALSERVER.listen(qApp.applicationName())
        if not ret:
            import os
            try:
                #todo not good way to remove /tmp/guiTimer.py
                os.remove('/tmp/' + qApp.applicationName())
                ret = LOCALSERVER.listen(qApp.applicationName())
            except:
                raise Exception(
                    'LOCALSERVER listen failed'
                    'you may need to remove /tmp/guiTimer.py manually')
        QObject.connect(LOCALSERVER, SIGNAL('newConnection()'), showMainWindow)
    else:
        print 'local socket connected'
        pass

    pass
Ejemplo n.º 4
0
def init():
    """Start listening to incoming connections."""
    global _server
    if _server is not None:
        return
    
    server = QLocalServer(None)
    
    # find a free socket name to use
    for name in ids():
        if server.listen(name):
            break
    else:
        # all names failed, try to contact and remove stale file if that fails
        socket = QLocalSocket()
        for name in ids():
            socket.connectToServer(name)
            if not socket.waitForConnected(10000):
                QLocalServer.removeServer(name)
                if server.listen(name):
                    break
            else:
                socket.disconnectFromServer()
        else:
            # no ids left, dont listen
            return
    app.aboutToQuit.connect(server.close)
    server.newConnection.connect(slot_new_connection)
    os.environ["FRESCOBALDI_SOCKET"] = ensure_bytes(name)
    _server = server
Ejemplo n.º 5
0
def testSingleInstanceOrExit():
    connected = False
    #try connect to QLocalServer
    local_sock = QLocalSocket()
    import sys
    QObject.connect(local_sock, SIGNAL('connected()'), sys.exit)
    connected = local_sock.connectToServer(qApp.applicationName())
    global LOCALSERVER
    if not connected:
        LOCALSERVER = QLocalServer()
        print 'setting up localserver', qApp.applicationName()
        ret = LOCALSERVER.listen(qApp.applicationName())
        if not ret:
            import os
            try:
                #todo not good way to remove /tmp/guiTimer.py
                os.remove('/tmp/'+qApp.applicationName())
                ret = LOCALSERVER.listen(qApp.applicationName())
            except:
                raise Exception('LOCALSERVER listen failed'
                        'you may need to remove /tmp/guiTimer.py manually')
        QObject.connect(LOCALSERVER, SIGNAL('newConnection()'), showMainWindow)
    else:
        print 'local socket connected'
        pass

    pass
Ejemplo n.º 6
0
def main():
    global win
    signal.signal(signal.SIGINT, exit)
    args = parse_arguments()
    appKey = "scudcloud.pid"
    socket = QLocalSocket()
    socket.connectToServer(appKey)
    if socket.isOpen():
        socket.close()
        socket.deleteLater()
        return 0
    socket.deleteLater()
    app = QtGui.QApplication(sys.argv)
    app.setApplicationName(Resources.APP_NAME+' Slack_SSB')
    app.setWindowIcon(QtGui.QIcon(Resources.get_path('scudcloud.png')))

    try:
        settings_path = load_settings(args.confdir)
    except:
        print("Configuration directory " + args.confdir +\
              " could not be created! Exiting...")
        raise SystemExit()
    minimized = True if args.minimized is True else None
    urgent_hint = True if args.urgent_hint is True else None

    win = sca.ScudCloud(debug=args.debug, minimized=minimized, urgent_hint=urgent_hint, settings_path=settings_path)
    app.commitDataRequest.connect(win.setForceClose, type=QtCore.Qt.DirectConnection)

    server = QLocalServer()
    server.newConnection.connect(restore)
    server.listen(appKey)
    win.restore()
    if win.minimized is None:
        win.show()
    sys.exit(app.exec_())
Ejemplo n.º 7
0
class SingleApplication(QApplication):
    messageAvailable = pyqtSignal(type(u''))

    def __init__(self, argv, key):
        QApplication.__init__(self, argv)

        self._key = key
        self._timeout = 1000

        socket = QLocalSocket(self)
        socket.connectToServer(self._key)
        if socket.waitForConnected(self._timeout):
            self._isRunning = True
            socket.abort()
            return
        socket.abort()

        self._isRunning = False
        self._server = QLocalServer(self)
        self._server.newConnection.connect(self.__onNewConnection)
        self._server.listen(self._key)

        self.aboutToQuit.connect(self.__onAboutToQuit)

    def __onAboutToQuit(self):
        if self._server:
            self._server.close()
            self._server = None

    def __onNewConnection(self):
        socket = self._server.nextPendingConnection()
        if socket.waitForReadyRead(self._timeout):
            self.messageAvailable.emit(socket.readAll().data().decode('utf-8'))
            socket.disconnectFromServer()
        else:
            pass

    def isRunning(self):
        return self._isRunning

    def sendMessage(self, message):
        assert(self._isRunning)

        if self.isRunning():
            socket = QLocalSocket(self)
            socket.connectToServer(self._key, QIODevice.WriteOnly)
            if not socket.waitForConnected(self._timeout):
                return False
            socket.write(message.encode('utf-8'))
            if not socket.waitForBytesWritten(self._timeout):
                return False
            socket.disconnectFromServer()
            return True
        return False
Ejemplo n.º 8
0
class SingleApplication(QApplication):
    messageAvailable = pyqtSignal(type(u''))

    def __init__(self, argv, key):
        QApplication.__init__(self, argv)

        self._key = key
        self._timeout = 1000

        socket = QLocalSocket(self)
        socket.connectToServer(self._key)
        if socket.waitForConnected(self._timeout):
            self._isRunning = True
            socket.abort()
            return
        socket.abort()

        self._isRunning = False
        self._server = QLocalServer(self)
        self._server.newConnection.connect(self.__onNewConnection)
        self._server.listen(self._key)

        self.aboutToQuit.connect(self.__onAboutToQuit)

    def __onAboutToQuit(self):
        if self._server:
            self._server.close()
            self._server = None

    def __onNewConnection(self):
        socket = self._server.nextPendingConnection()
        if socket.waitForReadyRead(self._timeout):
            self.messageAvailable.emit(socket.readAll().data().decode('utf-8'))
            socket.disconnectFromServer()
        else:
            pass

    def isRunning(self):
        return self._isRunning

    def sendMessage(self, message):
        assert (self._isRunning)

        if self.isRunning():
            socket = QLocalSocket(self)
            socket.connectToServer(self._key, QIODevice.WriteOnly)
            if not socket.waitForConnected(self._timeout):
                return False
            socket.write(message.encode('utf-8'))
            if not socket.waitForBytesWritten(self._timeout):
                return False
            socket.disconnectFromServer()
            return True
        return False
Ejemplo n.º 9
0
class Server(QObject):
    def __init__(self, parent=None):
        super(Server, self).__init__(parent)
        self.__m_server = None

    def __del__(self):
        if (self.__m_server != None):
            del self.__m_server

    def init(self, servername):

        if (self.__isServerRun(servername)):  #  如果已经有一个实例在运行了, 就返回0
            return  False

        self.__m_server = QLocalServer()

        """
          先移除原来存在的,
          如果不移除,那么如果 servername已经存在
          就会listen失败
        """

        QLocalServer.removeServer(servername)
        print "启动监听..."
        print self.__m_server.listen(servername)  # 进行监听

        self.connect(self.__m_server, SIGNAL("newConnection()"), self.__newConnection)
        return True

    def __newConnection(self):  #  有新的连接来了
        newsocket = self.__m_server.nextPendingConnection()
        self.connect(newsocket, SIGNAL("readyRead()"), self.readyRead)

    def readyRead(self):       #  可以读数据了
        local = self.sender()  #  取得是哪个localsocket可以读数据了
        if (local == None):
            return
        _in = QTextStream(local)
        readMsg = _in.readAll()
        print "recv Msg:",readMsg
        self.emit(SIGNAL("newMessage(QString)"), QString(readMsg))

    def __isServerRun(self, servername):  # 判断是否有一个同名的服务器在运行
        #  用一个localsocket去连一下,
        #  如果能连上就说明 有一个在运行了
        ls = QLocalSocket()

        ls.connectToServer(servername)
        if (ls.waitForConnected(1000)):
            ls.disconnectFromServer()  # // 说明已经在运行了
            ls.close()
            return  True
        return False
Ejemplo n.º 10
0
class Server(QObject):
    def __init__(self, parent=None):
        super(Server, self).__init__(parent)
        self.__m_server = None

    def __del__(self):
        if (self.__m_server != None):
            del self.__m_server

    def init(self, servername):

        if (self.__isServerRun(servername)):  #  如果已经有一个实例在运行了, 就返回0
            return False

        self.__m_server = QLocalServer()
        """
          先移除原来存在的,
          如果不移除,那么如果 servername已经存在
          就会listen失败
        """

        QLocalServer.removeServer(servername)
        print "启动监听..."
        print self.__m_server.listen(servername)  # 进行监听

        self.connect(self.__m_server, SIGNAL("newConnection()"),
                     self.__newConnection)
        return True

    def __newConnection(self):  #  有新的连接来了
        newsocket = self.__m_server.nextPendingConnection()
        self.connect(newsocket, SIGNAL("readyRead()"), self.readyRead)

    def readyRead(self):  #  可以读数据了
        local = self.sender()  #  取得是哪个localsocket可以读数据了
        if (local == None):
            return
        _in = QTextStream(local)
        readMsg = _in.readAll()
        print "recv Msg:", readMsg
        self.emit(SIGNAL("newMessage(QString)"), QString(readMsg))

    def __isServerRun(self, servername):  # 判断是否有一个同名的服务器在运行
        #  用一个localsocket去连一下,
        #  如果能连上就说明 有一个在运行了
        ls = QLocalSocket()

        ls.connectToServer(servername)
        if (ls.waitForConnected(1000)):
            ls.disconnectFromServer()  # // 说明已经在运行了
            ls.close()
            return True
        return False
Ejemplo n.º 11
0
class QSingleApplication(QApplication):
    def singleStart(self, mainWindow, pid):
        self.mainWindow = mainWindow
        self.pid = pid
        # Socket
        self.m_socket = QLocalSocket()
        self.m_socket.connected.connect(self.connectToExistingApp)
        self.m_socket.error.connect(self.startApplication)
        self.m_socket.connectToServer(pid, QIODevice.WriteOnly)

    def connectToExistingApp(self):
        if len(sys.argv) > 1 and sys.argv[1] is not None:
            self.m_socket.write(sys.argv[1])
            self.m_socket.bytesWritten.connect(self.quit)
        else:
            QMessageBox.warning(None, self.applicationName(),
                                self.tr("The program is already running."))
            # Quit application in 250 ms
            QTimer.singleShot(250, self.quit)

    def show(self):
        self.m_server.newConnection.connect(self.getNewConnection)
        if self.mainWindow.minimized is None:
            self.mainWindow.show()

    def startApplication(self):
        self.m_server = QLocalServer()
        if self.m_server.listen(self.pid):
            self.show()
        else:
            # Try one more time, now deleting the pid
            QLocalServer.removeServer(self.pid)
            if self.m_server.listen(self.pid):
                self.show()
            else:
                QMessageBox.critical(None, self.tr("Error"),
                                     self.tr("Error listening the socket."))

    def getNewConnection(self):
        self.new_socket = self.m_server.nextPendingConnection()
        self.new_socket.readyRead.connect(self.readSocket)

    def readSocket(self):
        f = self.new_socket.readLine()
        self.mainWindow.getArgsFromOtherInstance(str(f))
        self.mainWindow.activateWindow()
        self.mainWindow.show()
Ejemplo n.º 12
0
def main():
    global win
    signal.signal(signal.SIGINT, exit)
    args = parse_arguments()
    appKey = "scudcloud.pid"
    socket = QLocalSocket()
    socket.connectToServer(appKey)
    if socket.isOpen():
        socket.close()
        socket.deleteLater()
        return 0
    socket.deleteLater()
    app = QtGui.QApplication(sys.argv)
    app.setApplicationName(Resources.APP_NAME + ' Slack_SSB')
    app.setWindowIcon(QtGui.QIcon(Resources.get_path('scudcloud.png')))

    try:
        settings_path, cache_path = load_settings(args.confdir, args.cachedir)
    except:
        print("Data directories " + args.confdir + " and " + args.cachedir +
              " could not be created! Exiting...")
        raise SystemExit()
    minimized = True if args.minimized is True else None
    urgent_hint = True if args.urgent_hint is True else None

    # Let's move the CSS to cachedir to enable additional actions
    copyfile(Resources.get_path('resources.css'),
             os.path.join(cache_path, 'resources.css'))

    win = sca.ScudCloud(debug=args.debug,
                        minimized=minimized,
                        urgent_hint=urgent_hint,
                        settings_path=settings_path,
                        cache_path=cache_path)
    app.commitDataRequest.connect(win.setForceClose,
                                  type=QtCore.Qt.DirectConnection)

    server = QLocalServer()
    server.newConnection.connect(restore)
    server.listen(appKey)
    win.restore()
    if win.minimized is None:
        win.show()
    sys.exit(app.exec_())
Ejemplo n.º 13
0
class QSingleApplication(QApplication):
    def singleStart(self, mainWindow, pid):
        self.mainWindow = mainWindow
        self.pid = pid
        # Socket
        self.m_socket = QLocalSocket()
        self.m_socket.connected.connect(self.connectToExistingApp)
        self.m_socket.error.connect(self.startApplication)
        self.m_socket.connectToServer(pid, QIODevice.WriteOnly)
    def connectToExistingApp(self):
        if len(sys.argv)>1 and sys.argv[1] is not None:
            self.m_socket.write(sys.argv[1])
            self.m_socket.bytesWritten.connect(self.quit)
        else:
            QMessageBox.warning(None, self.applicationName(), self.tr("The program is already running."))
            # Quit application in 250 ms
            QTimer.singleShot(250, self.quit)
    def show(self):
        self.m_server.newConnection.connect(self.getNewConnection)
        if self.mainWindow.minimized is None:
            self.mainWindow.show()
    def startApplication(self):
        self.m_server = QLocalServer()
        if self.m_server.listen(self.pid):
            self.show()
        else:
            # Try one more time, now deleting the pid
            QLocalServer.removeServer(self.pid)
            if self.m_server.listen(self.pid):
                self.show()
            else:
                QMessageBox.critical(None, self.tr("Error"), self.tr("Error listening the socket."))
    def getNewConnection(self):
        self.new_socket = self.m_server.nextPendingConnection()
        self.new_socket.readyRead.connect(self.readSocket)
    def readSocket(self):
        f = self.new_socket.readLine()
        self.mainWindow.getArgsFromOtherInstance(str(f))
        self.mainWindow.activateWindow()
        self.mainWindow.show()
Ejemplo n.º 14
0
def main():
    app = QtGui.QApplication(sys.argv)
    androidToolsMainWin = AndroidToolsMainWindow()
    uiMainWidget = Ui_MainWidget()
    winOsArgv = WinCommandEnCoding.getOsArgv()
    # single QApplication solution
    # http://blog.csdn.net/softdzf/article/details/6704187
    serverName = 'AndroidToolsServer'
    clientSocket = QLocalSocket()
    clientSocket.connectToServer(serverName)
    QSettingsUtil.init()
    # 如果连接成功, 表明server 已经存在,当前已经有实例在运行, 将参数发送给服务端
    if clientSocket.waitForConnected(500):
        # print u'连接成功 arg = ', winOsArgv
        stream = QtCore.QTextStream(clientSocket)
        # for i in range(0, len(winOsArgv)):
        #     stream << winOsArgv[i]
        # 对于打开终端来说,所携带参数为第1位(打开文件的地址),第0位为本执行程序地址
        if len(winOsArgv) > 1:
            stream << winOsArgv[1]
            stream.setCodec('UTF-8')
            stream.flush()
            clientSocket.waitForBytesWritten()
        # close client socket
        clientSocket.close()
        return app.quit()
    # 如果没有实例执行,创建服务器
    localServer = QLocalServer()
    # 一直监听端口
    localServer.listen(serverName)
    # create db
    createDb()
    try:
        uiMainWidget.setupUi(androidToolsMainWin, localServer, winOsArgv)
        androidToolsMainWin.show()
        sys.exit(app.exec_())
    finally:
        localServer.close()
Ejemplo n.º 15
0
def main():
    app = QtGui.QApplication(sys.argv)
    ffstoreMainWin = FFStoreMainWindow()

    # set skin styleSheet
    # SkinHelper().setStyle(app, ':/qss/white_style.qss')
    SkinHelper().setStyle(app, ':/qss/dark_style.qss')

    # single QApplication solution
    # http://blog.csdn.net/softdzf/article/details/6704187
    serverName = 'FFStoreManagerServer'
    clientSocket = QLocalSocket()
    clientSocket.connectToServer(serverName)
    # 如果连接成功, 表明server 已经存在,当前已经有实例在运行, 将参数发送给服务端
    if clientSocket.waitForConnected(500):
        # print u'连接成功 arg = ', winOsArgv
        stream = QtCore.QTextStream(clientSocket)
        # for i in range(0, len(winOsArgv)):
        #     stream << winOsArgv[i]
        # 对于打开终端来说,所携带参数为第1位(打开文件的地址),第0位为本执行程序地址
        # close client socket
        clientSocket.close()
        return app.quit()
    # 如果没有实例执行,创建服务器
    localServer = QLocalServer()
    # 一直监听端口
    localServer.listen(serverName)
    # 初始化全局变量
    GlobalVar.init()
    try:
        showWindowLogic = ShowWindowLogic(mainWindow=ffstoreMainWin,
                                          localServer=localServer)
        showWindowLogic.show()
        # uiMainWidget.setupUi(mainWindow=ffstoreMainWin, localServer=localServer)
        # ffstoreMainWin.show()
        sys.exit(app.exec_())
    finally:
        localServer.close()
Ejemplo n.º 16
0
class QSingleton(QApplication):
    messageReceived = pyqtSignal()  # Señal de mensaje recibido

    #==================================================================================================================
    # CONSTRUCTOR DE LA CLASE
    #==================================================================================================================
    def __init__(self, appID, argv):
        #--------------------------------------------------------------------------------------------------------------
        # INICIAR LA CLASE
        #--------------------------------------------------------------------------------------------------------------
        super(QSingleton, self).__init__(argv)

        #--------------------------------------------------------------------------------------------------------------
        # CONFIGURACIONES INICIALES
        #--------------------------------------------------------------------------------------------------------------

        self.appID = appID
        self._outSocket = QLocalSocket()
        self._outSocket.connectToServer(self.appID)
        self._isRunning = self._outSocket.waitForConnected()

        # Si hay instancias previas corriendo
        if self._isRunning:
            self._outStream = QTextStream(self._outSocket)
            self._outStream.setCodec('UTF-8')

        # Si es la primera instancia
        else:
            self._outSocket = None
            self._outStream = None
            self._inSocket = None
            self._inStream = None
            self._server = QLocalServer()
            self._server.listen(self.appID)
            self._server.newConnection.connect(self._onNewConnection)

    #==================================================================================================================
    # MÉTODOS
    #==================================================================================================================

    # Método para saber si hay instancias previas ejecutandose
    def isRunning(self):
        return self._isRunning

    # Método para crear una nueva conexión
    def _onNewConnection(self):
        if self._inSocket:
            self._inSocket.readyRead.disconnect(self._onReadyRead)
        self._inSocket = self._server.nextPendingConnection()
        if not self._inSocket:
            return
        self._inStream = QTextStream(self._inSocket)
        self._inStream.setCodec('UTF-8')
        self._inSocket.readyRead.connect(self._onReadyRead)

    # Método para lectura del socket
    def _onReadyRead(self):
        while True:
            msg = self._inStream.readLine()
            if not msg: break
            self.messageReceived.emit(msg)
Ejemplo n.º 17
0
class __IDE(QMainWindow):
###############################################################################
# SIGNALS
#
# goingDown()
###############################################################################

    def __init__(self, start_server=False):
        QMainWindow.__init__(self)
        self.setWindowTitle('NINJA-IDE {Ninja-IDE Is Not Just Another IDE}')
        self.setMinimumSize(700, 500)
        #Load the size and the position of the main window
        self.load_window_geometry()

        #Start server if needed
        self.s_listener = None
        if start_server:
            self.s_listener = QLocalServer()
            self.s_listener.listen("ninja_ide")
            self.connect(self.s_listener, SIGNAL("newConnection()"),
                self._process_connection)

        #Profile handler
        self.profile = None
        #Opacity
        self.opacity = settings.MAX_OPACITY

        #Define Actions object before the UI
        self.actions = actions.Actions()
        #StatusBar
        self.status = status_bar.StatusBar(self)
        self.status.hide()
        self.setStatusBar(self.status)
        #Main Widget - Create first than everything else
        self.central = central_widget.CentralWidget(self)
        self.load_ui(self.central)
        self.setCentralWidget(self.central)

        #ToolBar
        self.toolbar = QToolBar(self)
        self.toolbar.setToolTip(self.tr("Press and Drag to Move"))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.addToolBar(settings.TOOLBAR_AREA, self.toolbar)
        if settings.HIDE_TOOLBAR:
            self.toolbar.hide()

        #Install Shortcuts after the UI has been initialized
        self.actions.install_shortcuts(self)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
            self.actions.update_explorer)

        #Menu
        menubar = self.menuBar()
        file_ = menubar.addMenu(self.tr("&File"))
        edit = menubar.addMenu(self.tr("&Edit"))
        view = menubar.addMenu(self.tr("&View"))
        source = menubar.addMenu(self.tr("&Source"))
        project = menubar.addMenu(self.tr("&Project"))
        self.pluginsMenu = menubar.addMenu(self.tr("&Addins"))
        about = menubar.addMenu(self.tr("Abou&t"))

        #The order of the icons in the toolbar is defined by this calls
        self._menuFile = menu_file.MenuFile(file_, self.toolbar, self)
        self._menuView = menu_view.MenuView(view, self.toolbar, self)
        self._menuEdit = menu_edit.MenuEdit(edit, self.toolbar)
        self._menuSource = menu_source.MenuSource(source)
        self._menuProject = menu_project.MenuProject(project, self.toolbar)
        self._menuPlugins = menu_plugins.MenuPlugins(self.pluginsMenu)
        self._menuAbout = menu_about.MenuAbout(about)

        self.load_toolbar()

        #Plugin Manager
        services = {
            'editor': plugin_services.MainService(),
            'toolbar': plugin_services.ToolbarService(self.toolbar),
            'menuApp': plugin_services.MenuAppService(self.pluginsMenu),
            'explorer': plugin_services.ExplorerService(),
            'misc': plugin_services.MiscContainerService(self.misc)}
        serviceLocator = plugin_manager.ServiceLocator(services)
        self.plugin_manager = plugin_manager.PluginManager(resources.PLUGINS,
            serviceLocator)
        self.plugin_manager.discover()
        #load all plugins!
        self.plugin_manager.load_all()

        #Tray Icon
        self.trayIcon = updates.TrayIconUpdates(self)
        self.trayIcon.show()

        self.connect(self._menuFile, SIGNAL("openFile(QString)"),
            self.mainContainer.open_file)
        self.connect(self.mainContainer, SIGNAL("fileSaved(QString)"),
            self.show_status_message)
        self.connect(self.mainContainer,
            SIGNAL("recentTabsModified(QStringList)"),
            self._menuFile.update_recent_files)

    def _process_connection(self):
        connection = self.s_listener.nextPendingConnection()
        connection.waitForReadyRead()
        data = connection.readAll()
        connection.close()
        if data:
            files, projects = data.split(ipc.project_delimiter, 1)
            files = map(lambda x: (x.split(':')[0], int(x.split(':')[1])),
                files.split(ipc.file_delimiter))
            projects = projects.split(ipc.project_delimiter)
            self.load_session_files_projects(files, [], projects, None)

    def load_toolbar(self):
        self.toolbar.clear()
        toolbar_items = {}
        toolbar_items.update(self._menuFile.toolbar_items)
        toolbar_items.update(self._menuView.toolbar_items)
        toolbar_items.update(self._menuEdit.toolbar_items)
        toolbar_items.update(self._menuSource.toolbar_items)
        toolbar_items.update(self._menuProject.toolbar_items)

        for item in settings.TOOLBAR_ITEMS:
            if item == 'separator':
                self.toolbar.addSeparator()
            else:
                tool_item = toolbar_items.get(item, None)
                if tool_item is not None:
                    self.toolbar.addAction(tool_item)
        #load action added by plugins, This is a special case when reload
        #the toolbar after save the preferences widget
        for toolbar_action in settings.get_toolbar_item_for_plugins():
            self.toolbar.addAction(toolbar_action)

    def load_external_plugins(self, paths):
        for path in paths:
            self.plugin_manager.add_plugin_dir(path)
        #load all plugins!
        self.plugin_manager.discover()
        self.plugin_manager.load_all()

    def show_status_message(self, message):
        self.status.showMessage(message, 2000)

    def load_ui(self, centralWidget):
        #Set Application Font for ToolTips
        QToolTip.setFont(QFont(settings.FONT_FAMILY, 10))
        #Create Main Container to manage Tabs
        self.mainContainer = main_container.MainContainer(self)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
            self.change_window_title)
        self.connect(self.mainContainer,
            SIGNAL("locateFunction(QString, QString, bool)"),
            self.actions.locate_function)
        self.connect(self.mainContainer,
            SIGNAL("navigateCode(bool, int)"),
            self.actions.navigate_code_history)
        self.connect(self.mainContainer,
            SIGNAL("addBackItemNavigation()"),
            self.actions.add_back_item_navigation)
        self.connect(self.mainContainer, SIGNAL("updateFileMetadata()"),
            self.actions.update_explorer)
        self.connect(self.mainContainer, SIGNAL("updateLocator(QString)"),
            self.actions.update_explorer)
        self.connect(self.mainContainer, SIGNAL("openPreferences()"),
            self._show_preferences)
        self.connect(self.mainContainer, SIGNAL("dontOpenStartPage()"),
            self._dont_show_start_page_again)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
            self.status.handle_tab_changed)
        # Update symbols
        self.connect(self.mainContainer, SIGNAL("updateLocator(QString)"),
            self.status.explore_file_code)
        #Create Explorer Panel
        self.explorer = explorer_container.ExplorerContainer(self)
        self.connect(self.central, SIGNAL("splitterCentralRotated()"),
            self.explorer.rotate_tab_position)
        self.connect(self.explorer, SIGNAL("updateLocator()"),
            self.status.explore_code)
        self.connect(self.explorer, SIGNAL("goToDefinition(int)"),
            self.actions.editor_go_to_line)
        self.connect(self.explorer, SIGNAL("projectClosed(QString)"),
            self.actions.close_files_from_project)
        #Create Misc Bottom Container
        self.misc = misc_container.MiscContainer(self)
        self.connect(self.mainContainer, SIGNAL("findOcurrences(QString)"),
            self.misc.show_find_occurrences)

        centralWidget.insert_central_container(self.mainContainer)
        centralWidget.insert_lateral_container(self.explorer)
        centralWidget.insert_bottom_container(self.misc)
        self.connect(self.mainContainer,
            SIGNAL("cursorPositionChange(int, int)"),
            self.central.lateralPanel.update_line_col)
        # TODO: Change current symbol on move
        #self.connect(self.mainContainer,
            #SIGNAL("cursorPositionChange(int, int)"),
            #self.explorer.update_current_symbol)
        self.connect(self.mainContainer, SIGNAL("enabledFollowMode(bool)"),
            self.central.enable_follow_mode_scrollbar)

        if settings.SHOW_START_PAGE:
            self.mainContainer.show_start_page()

    def _show_preferences(self):
        pref = preferences.PreferencesWidget(self.mainContainer)
        pref.show()

    def _dont_show_start_page_again(self):
        settings.SHOW_START_PAGE = False
        qsettings = QSettings()
        qsettings.beginGroup('preferences')
        qsettings.beginGroup('general')
        qsettings.setValue('showStartPage', settings.SHOW_START_PAGE)
        qsettings.endGroup()
        qsettings.endGroup()
        self.mainContainer.actualTab.close_tab()

    def load_session_files_projects(self, filesTab1, filesTab2, projects,
        current_file, recent_files=None):
        self.mainContainer.open_files(filesTab1, notIDEStart=False)
        self.mainContainer.open_files(filesTab2, mainTab=False,
            notIDEStart=False)
        self.explorer.open_session_projects(projects, notIDEStart=False)
        if current_file:
            self.mainContainer.open_file(current_file, notStart=False)
        if recent_files is not None:
            self._menuFile.update_recent_files(recent_files)

    def open_file(self, filename):
        if filename:
            self.mainContainer.open_file(filename)

    def open_project(self, project):
        if project:
            self.actions.open_project(project)

    def __get_profile(self):
        return self.profile

    def __set_profile(self, profileName):
        self.profile = profileName
        if self.profile is not None:
            self.setWindowTitle('NINJA-IDE (PROFILE: %s)' % self.profile)
        else:
            self.setWindowTitle(
                'NINJA-IDE {Ninja-IDE Is Not Just Another IDE}')

    Profile = property(__get_profile, __set_profile)

    def change_window_title(self, title):
        if self.profile is None:
            self.setWindowTitle('NINJA-IDE - %s' % title)
        else:
            self.setWindowTitle('NINJA-IDE (PROFILE: %s) - %s' % (
                self.profile, title))
        currentEditor = self.mainContainer.get_actual_editor()
        if currentEditor is not None:
            line = currentEditor.textCursor().blockNumber() + 1
            col = currentEditor.textCursor().columnNumber()
            self.central.lateralPanel.update_line_col(line, col)

    def wheelEvent(self, event):
        if event.modifiers() == Qt.ShiftModifier:
            if event.delta() == 120 and self.opacity < settings.MAX_OPACITY:
                self.opacity += 0.1
            elif event.delta() == -120 and self.opacity > settings.MIN_OPACITY:
                self.opacity -= 0.1
            self.setWindowOpacity(self.opacity)
            event.ignore()
        else:
            QMainWindow.wheelEvent(self, event)

    def save_settings(self):
        """Save the settings before the application is closed with QSettings.

        Info saved: Tabs and projects opened, windows state(size and position).
        """
        qsettings = QSettings()
        editor_widget = self.mainContainer.get_actual_editor()
        current_file = ''
        if editor_widget is not None:
            current_file = editor_widget.ID
        if qsettings.value('preferences/general/loadFiles', 'true') == 'true':
            openedFiles = self.mainContainer.get_opened_documents()
            projects_obj = self.explorer.get_opened_projects()
            projects = [p.path for p in projects_obj]
            qsettings.setValue('openFiles/projects',
                projects)
            if len(openedFiles) > 0:
                qsettings.setValue('openFiles/mainTab', openedFiles[0])
            if len(openedFiles) == 2:
                qsettings.setValue('openFiles/secondaryTab', openedFiles[1])
            qsettings.setValue('openFiles/currentFile', current_file)
            qsettings.setValue('openFiles/recentFiles',
                self.mainContainer._tabMain.get_recent_files_list())
        qsettings.setValue('preferences/editor/bookmarks', settings.BOOKMARKS)
        qsettings.setValue('preferences/editor/breakpoints',
            settings.BREAKPOINTS)
        qsettings.setValue('preferences/general/toolbarArea',
            self.toolBarArea(self.toolbar))
        #Save if the windows state is maximixed
        if(self.isMaximized()):
            qsettings.setValue("window/maximized", True)
        else:
            qsettings.setValue("window/maximized", False)
            #Save the size and position of the mainwindow
            qsettings.setValue("window/size", self.size())
            qsettings.setValue("window/pos", self.pos())
        #Save the size of de splitters
        qsettings.setValue("window/central/areaSize",
            self.central.get_area_sizes())
        qsettings.setValue("window/central/mainSize",
            self.central.get_main_sizes())
        #Save the toolbar visibility
        qsettings.setValue("window/hide_toolbar", not self.toolbar.isVisible())
        #Save Profiles
        if self.profile is not None:
            self.actions.save_profile(self.profile)
        else:
            qsettings.setValue('ide/profiles', settings.PROFILES)

    def load_window_geometry(self):
        """Load from QSettings the window size of de Ninja IDE"""
        qsettings = QSettings()
        if qsettings.value("window/maximized", 'true') == 'true':
            self.setWindowState(Qt.WindowMaximized)
        else: 
            print dir(QSizeF) 


            self.resize(qsettings.value("window/size",
                QSizeF(800, 600)).toSize())
            self.move(qsettings.value("window/pos",
                QPointF(100, 100)).toPoint())

    def closeEvent(self, event):
        if self.s_listener:
            self.s_listener.close()
        if settings.CONFIRM_EXIT and \
        self.mainContainer.check_for_unsaved_tabs():
            unsaved_files = self.mainContainer.get_unsaved_files()
            txt = '\n'.join(unsaved_files)
            val = QMessageBox.question(self,
                self.tr("Some changes were not saved"),
                self.tr("%s\n\nDo you want to exit anyway?" % txt),
                QMessageBox.Yes, QMessageBox.No)
            if val == QMessageBox.No:
                event.ignore()
        QApplication.instance().setCursorFlashTime(cursor_flash_time)
        self.emit(SIGNAL("goingDown()"))
        self.save_settings()
        completion_daemon.shutdown_daemon()
        #close python documentation server (if running)
        self.mainContainer.close_python_doc()
        #Shutdown PluginManager
        self.plugin_manager.shutdown()

    def notify_plugin_errors(self):
        errors = self.plugin_manager.errors
        if errors:
            plugin_error_dialog = traceback_widget.PluginErrorDialog()
            for err_tuple in errors:
                plugin_error_dialog.add_traceback(err_tuple[0], err_tuple[1])
            #show the dialog
            plugin_error_dialog.exec_()
Ejemplo n.º 18
0
class IDE(QMainWindow):
    """This class is like the Sauron's Ring:
    One ring to rule them all, One ring to find them,
    One ring to bring them all and in the darkness bind them.

    This Class knows all the containers, and its know by all the containers,
    but the containers don't need to know between each other, in this way we
    can keep a better api without the need to tie the behaviour between
    the widgets, and let them just consume the 'actions' they need."""

    ###############################################################################
    # SIGNALS
    #
    # goingDown()
    ###############################################################################

    __IDESERVICES = {}
    __IDECONNECTIONS = {}
    __IDESHORTCUTS = {}
    __IDEBARCATEGORIES = {}
    __IDEMENUS = {}
    __IDETOOLBAR = {}
    # CONNECTIONS structure:
    # ({'target': service_name, 'signal_name': string, 'slot': function_obj},)
    # On modify add: {connected: True}
    __instance = None
    __created = False

    def __init__(self, start_server=False):
        QMainWindow.__init__(self)
        self.setWindowTitle('NINJA-IDE {Ninja-IDE Is Not Just Another IDE}')
        self.setMinimumSize(750, 500)
        QToolTip.setFont(QFont(settings.FONT_FAMILY, 10))
        #Load the size and the position of the main window
        self.load_window_geometry()
        self.__project_to_open = 0

        #Editables
        self.__neditables = {}
        #Filesystem
        self.filesystem = nfilesystem.NVirtualFileSystem()

        #Start server if needed
        self.s_listener = None
        if start_server:
            self.s_listener = QLocalServer()
            self.s_listener.listen("ninja_ide")
            self.connect(self.s_listener, SIGNAL("newConnection()"),
                         self._process_connection)

        #Profile handler
        self.profile = None
        #Opacity
        self.opacity = settings.MAX_OPACITY

        #ToolBar
        self.toolbar = QToolBar(self)
        self.toolbar.setToolTip(self.tr("Press and Drag to Move"))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.addToolBar(settings.TOOLBAR_AREA, self.toolbar)
        if settings.HIDE_TOOLBAR:
            self.toolbar.hide()
        #Notificator
        self.notification = notification.Notification(self)

        #Plugin Manager
        #services = {
        #'editor': plugin_services.MainService(),
        #'toolbar': plugin_services.ToolbarService(self.toolbar),
        ##'menuApp': plugin_services.MenuAppService(self.pluginsMenu),
        #'menuApp': plugin_services.MenuAppService(None),
        #'explorer': plugin_services.ExplorerService(),
        #'misc': plugin_services.MiscContainerService(self.misc)}
        #serviceLocator = plugin_manager.ServiceLocator(services)
        serviceLocator = plugin_manager.ServiceLocator(None)
        self.plugin_manager = plugin_manager.PluginManager(
            resources.PLUGINS, serviceLocator)
        self.plugin_manager.discover()
        #load all plugins!
        self.plugin_manager.load_all()

        #Tray Icon
        self.trayIcon = updates.TrayIconUpdates(self)
        self.connect(self.trayIcon, SIGNAL("closeTrayIcon()"),
                     self._close_tray_icon)
        self.trayIcon.show()

        key = Qt.Key_1
        for i in range(10):
            if settings.IS_MAC_OS:
                short = ui_tools.TabShortcuts(
                    QKeySequence(Qt.CTRL + Qt.ALT + key), self, i)
            else:
                short = ui_tools.TabShortcuts(QKeySequence(Qt.ALT + key), self,
                                              i)
            key += 1
            self.connect(short, SIGNAL("activated()"), self._change_tab_index)
        short = ui_tools.TabShortcuts(QKeySequence(Qt.ALT + Qt.Key_0), self,
                                      10)
        self.connect(short, SIGNAL("activated()"), self._change_tab_index)

        # Register menu categories
        IDE.register_bar_category(translations.TR_MENU_FILE, 100)
        IDE.register_bar_category(translations.TR_MENU_EDIT, 110)
        IDE.register_bar_category(translations.TR_MENU_VIEW, 120)
        IDE.register_bar_category(translations.TR_MENU_SOURCE, 130)
        IDE.register_bar_category(translations.TR_MENU_PROJECT, 140)
        IDE.register_bar_category(translations.TR_MENU_ADDINS, 150)
        IDE.register_bar_category(translations.TR_MENU_ABOUT, 160)
        # Register General Menu Items
        ui_tools.install_shortcuts(self, actions.ACTIONS_GENERAL, self)

        self.register_service('ide', self)
        self.register_service('toolbar', self.toolbar)
        #Register signals connections
        connections = (
            {
                'target': 'main_container',
                'signal_name': 'fileSaved(QString)',
                'slot': self.show_status_message
            },
            {
                'target': 'main_container',
                'signal_name': 'currentEditorChanged(QString)',
                'slot': self.change_window_title
            },
            {
                'target': 'main_container',
                'signal_name': 'openPreferences()',
                'slot': self.show_preferences
            },
            {
                'target': 'main_container',
                'signal_name': 'allTabsClosed()',
                'slot': self._last_tab_closed
            },
            {
                'target': 'explorer_container',
                'signal_name': 'changeWindowTitle(QString)',
                'slot': self.change_window_title
            },
            {
                'target': 'explorer_container',
                'signal_name': 'projectClosed(QString)',
                'slot': self.close_project
            },
        )
        self.register_signals('ide', connections)
        # Central Widget MUST always exists
        self.central = IDE.get_service('central_container')
        self.setCentralWidget(self.central)
        # Install Services
        for service_name in self.__IDESERVICES:
            self.install_service(service_name)
        self.__created = True
        menu_bar = IDE.get_service('menu_bar')
        if menu_bar:
            menu_bar.load_menu(self)
            #These two are the same service, I think that's ok
            menu_bar.load_toolbar(self)

    @classmethod
    def get_service(cls, service_name):
        """Return the instance of a registered service."""
        return cls.__IDESERVICES.get(service_name, None)

    def get_menuitems(self):
        """Return a dictionary with the registered menu items."""
        return self.__IDEMENUS

    def get_bar_categories(self):
        """Get the registered Categories for the Application menus."""
        return self.__IDEBARCATEGORIES

    def get_toolbaritems(self):
        """Return a dictionary with the registered menu items."""
        return self.__IDETOOLBAR

    @classmethod
    def register_service(cls, service_name, obj):
        """Register a service providing the service name and the instance."""
        cls.__IDESERVICES[service_name] = obj
        if cls.__created:
            cls.__instance.install_service(service_name)

    def install_service(self, service_name):
        """Activate the registered service."""
        obj = self.__IDESERVICES.get(service_name, None)
        func = getattr(obj, 'install', None)
        if isinstance(func, collections.Callable):
            func()
        self._connect_signals()

    def place_me_on(self, name, obj, region="central", top=False):
        """Place a widget in some of the areas in the IDE.
        @name: id to access to that widget later if needed.
        @obj: the instance of the widget to be placed.
        @region: the area where to put the widget [central, lateral]
        @top: place the widget as the first item in the split."""
        self.central.add_to_region(name, obj, region, top)

    @classmethod
    def register_signals(cls, service_name, connections):
        """Register all the signals that a particular service wants to be
        attached of.
        @service_name: id of the service
        @connections: list of dictionaries for the connection with:
            - 'target': 'the_other_service_name',
            - 'signal_name': 'name of the signal in the other service',
            - 'slot': function object in this service"""
        cls.__IDECONNECTIONS[service_name] = connections
        if cls.__created:
            cls.__instance._connect_signals()

    def _connect_signals(self):
        """Connect the signals between the different services."""
        for service_name in self.__IDECONNECTIONS:
            connections = self.__IDECONNECTIONS[service_name]
            for connection in connections:
                if connection.get('connected', False):
                    continue
                target = self.__IDESERVICES.get(connection['target'], None)
                slot = connection['slot']
                signal_name = connection['signal_name']
                if target and isinstance(slot, collections.Callable):
                    self.connect(target, SIGNAL(signal_name), slot)
                    connection['connected'] = True

    @classmethod
    def register_shortcut(cls, shortcut_name, shortcut, action=None):
        """Register a shortcut and action."""
        cls.__IDESHORTCUTS[shortcut_name] = (shortcut, action)

    @classmethod
    def register_menuitem(cls, menu_action, section, weight):
        """Register a QAction or QMenu in the IDE to be loaded later in the
        menubar using the section(string) to define where is going to be
        contained, and the weight define the order where is going to be
        placed.
        @menu_action: QAction or QMenu
        @section: String (name)
        @weight: int"""
        cls.__IDEMENUS[menu_action] = (section, weight)

    @classmethod
    def register_toolbar(cls, action, section, weight):
        """Register a QAction in the IDE to be loaded later in the
        toolbar using the section(string) to define where is going to be
        contained, and the weight define the order where is going to be
        placed.
        @action: QAction
        @section: String (name)
        @weight: int"""
        cls.__IDETOOLBAR[action] = (section, weight)

    @classmethod
    def register_bar_category(cls, category_name, weight):
        """Register a Menu Category to be created with the proper weight.
        @category_name: string
        @weight: int"""
        cls.__IDEBARCATEGORIES[category_name] = weight

    @classmethod
    def update_shortcut(cls, shortcut_name):
        """Update all the shortcuts of the application."""
        short = resources.get_shortcut
        shortcut, action = cls.__IDESHORTCUTS.get(shortcut_name)
        if shortcut:
            shortcut.setKey(short(shortcut_name))
        if action:
            action.setShortcut(short(shortcut_name))

    def get_or_create_editable(self, filename):
        nfile = self.filesystem.get_file(nfile_path=filename)
        editable = self.__neditables.get(nfile)
        if editable is None:
            editable = neditable.NEditable(nfile)
            self.__neditables[nfile] = editable
        return editable

    def get_project_for_file(self, filename):
        project = None
        if filename:
            project = self.filesystem.get_project_for_file(filename)
        return project

    def create_project(self, path):
        nproj = nproject.NProject(path)
        self.filesystem.open_project(nproj)
        return nproj

    def close_project(self, project_path):
        self.filesystem.close_project(project_path)

    def get_projects(self):
        return self.filesystem.get_projects()

    def get_current_project(self):
        current_project = None
        projects = self.filesystem.get_projects()
        for project in projects:
            if projects[project].is_current:
                current_project = projects[project]
                break
        return current_project

    def select_current(self, widget):
        """Show the widget with a 4px lightblue border line."""
        self.setProperty("highlight", True)
        self.style().unpolish(self)
        self.style().polish(self)

    def unselect_current(self, widget):
        """Remove the 4px lightblue border line from the widget."""
        self.setProperty("highlight", False)
        self.style().unpolish(widget)
        self.style().polish(widget)

    def get_opened_projects(self):
        return self.__projects

    def _close_tray_icon(self):
        """Close the System Tray Icon."""
        self.trayIcon.hide()
        self.trayIcon.deleteLater()

    def _change_tab_index(self):
        """Change the tabs of the current TabWidget using alt+numbers."""
        widget = QApplication.focusWidget()
        shortcut_index = getattr(widget, 'shortcut_index', None)
        if shortcut_index:
            obj = self.sender()
            shortcut_index(obj.index)

    def switch_focus(self):
        """Switch the current keyboard focus to the next widget."""
        widget = QApplication.focusWidget()
        main_container = IDE.get_service('main_container')
        tools_dock = IDE.get_service('tools_dock')
        explorer_container = IDE.get_service('explorer_container')
        if widget and main_container and tools_dock and explorer_container:
            if widget in (main_container.actualTab,
                          main_container.actualTab.currentWidget()):
                explorer_container.currentWidget().setFocus()
            elif widget in (explorer_container,
                            explorer_container.currentWidget()):
                if tools_dock.isVisible():
                    tools_dock.stack.currentWidget().setFocus()
                else:
                    main_container.actualTab.currentWidget().setFocus()
            elif widget.parent() is tools_dock.stack:
                main_container.actualTab.currentWidget().setFocus()

    def _process_connection(self):
        """Read the ipc input from another instance of ninja."""
        connection = self.s_listener.nextPendingConnection()
        connection.waitForReadyRead()
        data = connection.readAll()
        connection.close()
        if data:
            files, projects = str(data).split(ipc.project_delimiter, 1)
            files = [(x.split(':')[0], int(x.split(':')[1]))
                     for x in files.split(ipc.file_delimiter)]
            projects = projects.split(ipc.project_delimiter)
            self.load_session_files_projects(files, [], projects, None)

    def fullscreen_mode(self):
        """Change to fullscreen mode."""
        if self.isFullScreen():
            self.showMaximized()
        else:
            self.showFullScreen()

    def change_toolbar_visibility(self):
        """Switch the toolbar visibility"""
        if self.toolbar.isVisible():
            self.toolbar.hide()
        else:
            self.toolbar.show()

    def load_external_plugins(self, paths):
        """Load external plugins, the ones added to ninja throw the cmd."""
        for path in paths:
            self.plugin_manager.add_plugin_dir(path)
        #load all plugins!
        self.plugin_manager.discover()
        self.plugin_manager.load_all()

    def _last_tab_closed(self):
        """
        Called when the last tasb is closed
        """
        self.explorer.cleanup_tabs()

    def show_preferences(self):
        """Open the Preferences Dialog."""
        pref = preferences.PreferencesWidget(self)
        pref.show()

    def load_session_files_projects(self,
                                    filesTab1,
                                    filesTab2,
                                    projects,
                                    current_file,
                                    recent_files=None):
        """Load the files and projects from previous session."""
        self.__project_to_open = len(projects)
        explorer = IDE.get_service('explorer_container')
        main_container = IDE.get_service('main_container')
        if explorer and main_container:
            self.connect(explorer, SIGNAL("projectOpened(QString)"),
                         self._set_editors_project_data)
            explorer.open_session_projects(projects, notIDEStart=False)
            main_container.open_files(filesTab1, notIDEStart=False)
            main_container.open_files(filesTab2,
                                      mainTab=False,
                                      notIDEStart=False)
            if current_file:
                main_container.open_file(current_file, notStart=False)
            #if recent_files is not None:
            #menu_file = IDE.get_service('menu_file')
            #menu_file.update_recent_files(recent_files)

    #def _set_editors_project_data(self):
    #self.__project_to_open -= 1
    #if self.__project_to_open == 0:
    #self.disconnect(self.explorer, SIGNAL("projectOpened(QString)"),
    #self._set_editors_project_data)
    #self.mainContainer.update_editor_project()

    #def open_file(self, filename):
    #if filename:
    #self.mainContainer.open_file(filename)

    #def open_project(self, project):
    #if project:
    #self.actions.open_project(project)

    def __get_profile(self):
        return self.profile

    def __set_profile(self, profileName):
        self.profile = profileName
        if self.profile is not None:
            self.setWindowTitle('NINJA-IDE (PROFILE: %s)' % self.profile)
        else:
            self.setWindowTitle(
                'NINJA-IDE {Ninja-IDE Is Not Just Another IDE}')

    Profile = property(__get_profile, __set_profile)

    def change_window_title(self, title):
        """Change the title of the Application."""
        if self.profile is None:
            self.setWindowTitle('NINJA-IDE - %s' % title)
        else:
            self.setWindowTitle('NINJA-IDE (PROFILE: %s) - %s' %
                                (self.profile, title))

    def wheelEvent(self, event):
        """Change the opacity of the application."""
        if event.modifiers() == Qt.ShiftModifier:
            if event.delta() == 120 and self.opacity < settings.MAX_OPACITY:
                self.opacity += 0.1
            elif event.delta() == -120 and self.opacity > settings.MIN_OPACITY:
                self.opacity -= 0.1
            self.setWindowOpacity(self.opacity)
            event.ignore()
        else:
            QMainWindow.wheelEvent(self, event)

    def save_settings(self):
        """Save the settings before the application is closed with QSettings.

        Info saved: Tabs and projects opened, windows state(size and position).
        """
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        editor_widget = self.mainContainer.get_actual_editor()
        current_file = ''
        if editor_widget is not None:
            current_file = editor_widget.ID
        if qsettings.value('preferences/general/loadFiles', True, type=bool):
            openedFiles = self.mainContainer.get_opened_documents()
            projects_obj = self.get_opened_projects()
            projects = [p.path for p in projects_obj]
            qsettings.setValue('openFiles/projects', projects)
            if len(openedFiles) > 0:
                qsettings.setValue('openFiles/mainTab', openedFiles[0])
            if len(openedFiles) == 2:
                qsettings.setValue('openFiles/secondaryTab', openedFiles[1])
            qsettings.setValue('openFiles/currentFile', current_file)
            qsettings.setValue(
                'openFiles/recentFiles',
                self.mainContainer._tabMain.get_recent_files_list())
        qsettings.setValue('preferences/editor/bookmarks', settings.BOOKMARKS)
        qsettings.setValue('preferences/editor/breakpoints',
                           settings.BREAKPOINTS)
        qsettings.setValue('preferences/general/toolbarArea',
                           self.toolBarArea(self.toolbar))
        #Save if the windows state is maximixed
        if (self.isMaximized()):
            qsettings.setValue("window/maximized", True)
        else:
            qsettings.setValue("window/maximized", False)
            #Save the size and position of the mainwindow
            qsettings.setValue("window/size", self.size())
            qsettings.setValue("window/pos", self.pos())
        #Save the size of de splitters
        qsettings.setValue("window/central/baseSize",
                           self.central.get_area_sizes())
        qsettings.setValue("window/central/insideSize",
                           self.central.get_main_sizes())
        #Save the toolbar visibility
        if not self.toolbar.isVisible() and self.menuBar().isVisible():
            qsettings.setValue("window/hide_toolbar", True)
        else:
            qsettings.setValue("window/hide_toolbar", False)
        #Save Misc state
        qsettings.setValue("window/show_region1", self.misc.isVisible())
        #Save Profiles
        if self.profile is not None:
            self.actions.save_profile(self.profile)
        else:
            qsettings.setValue('ide/profiles', settings.PROFILES)

    def create_profile(self):
        """Create a profile binding files and projects to a key."""
        profileInfo = QInputDialog.getText(
            None, self.tr("Create Profile"),
            self.tr("The Current Files and Projects will "
                    "be associated to this profile.\n"
                    "Profile Name:"))
        if profileInfo[1]:
            profileName = profileInfo[0]
            if not profileName or profileName in settings.PROFILES:
                QMessageBox.information(
                    self, self.tr("Profile Name Invalid"),
                    self.tr("The Profile name is invalid or already exists."))
                return
            self.save_profile(profileName)
            return profileName

    def save_profile(self, profileName):
        """Save the updates from a profile."""
        ide = IDE.get_service('ide')
        main_container = IDE.get_service('main_container')
        if main_container:
            projects_obj = ide.get_opened_projects()
            projects = [p.path for p in projects_obj]
            files = main_container.get_opened_documents()
            files = files[0] + files[1]
            settings.PROFILES[profileName] = [files, projects]
            qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
            qsettings.setValue('ide/profiles', settings.PROFILES)

    def activate_profile(self):
        """Show the Profile Manager dialog."""
        profilesLoader = ui_tools.ProfilesLoader(self._load_profile_data,
                                                 self.create_profile,
                                                 self.save_profile,
                                                 settings.PROFILES, self.ide)
        profilesLoader.show()

    def deactivate_profile(self):
        """Close the Profile Session."""
        self.Profile = None

    def _load_profile_data(self, key):
        """Activate the selected profile, closing the current files/projects"""
        explorer = IDE.get_service('explorer_container')
        main_container = IDE.get_service('main_container')
        if explorer and main_container:
            explorer.close_opened_projects()
            main_container.open_files(settings.PROFILES[key][0])
            explorer.open_session_projects(settings.PROFILES[key][1])

    def load_window_geometry(self):
        """Load from QSettings the window size of de Ninja IDE"""
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        if qsettings.value("window/maximized", True, type=bool):
            self.setWindowState(Qt.WindowMaximized)
        else:
            self.resize(
                qsettings.value("window/size",
                                QSizeF(800, 600).toSize(),
                                type='QSize'))
            self.move(
                qsettings.value("window/pos",
                                QPointF(100, 100).toPoint(),
                                type='QPoint'))

    def closeEvent(self, event):
        """Saves some global settings before closing."""
        if self.s_listener:
            self.s_listener.close()
        #if (settings.CONFIRM_EXIT and
        #self.mainContainer.check_for_unsaved_tabs()):
        #unsaved_files = self.mainContainer.get_unsaved_files()
        #txt = '\n'.join(unsaved_files)
        #val = QMessageBox.question(self,
        #self.tr("Some changes were not saved"),
        #(self.tr("%s\n\nDo you want to save them?") % txt),
        #QMessageBox.Yes, QMessageBox.No, QMessageBox.Cancel)
        #if val == QMessageBox.Yes:
        ##Saves all open files
        #main_container = IDE.get_service('main_container')
        #if main_container:
        #main_container.save_all()
        #if val == QMessageBox.Cancel:
        #event.ignore()
        #self.emit(SIGNAL("goingDown()"))
        #self.save_settings()
        #completion_daemon.shutdown_daemon()
        ##close python documentation server (if running)
        #self.mainContainer.close_python_doc()
        ##Shutdown PluginManager
        self.plugin_manager.shutdown()
        super(IDE, self).closeEvent(event)

    def notify_plugin_errors(self):
        #TODO: Check if the Plugin Error dialog can be improved
        errors = self.plugin_manager.errors
        if errors:
            plugin_error_dialog = traceback_widget.PluginErrorDialog()
            for err_tuple in errors:
                plugin_error_dialog.add_traceback(err_tuple[0], err_tuple[1])
            #show the dialog
            plugin_error_dialog.exec_()

    def show_status_message(self, message, duration=3000):
        """Show status message."""
        self.notification.set_message(message, duration)
        self.notification.show()

    def show_manager(self):
        """Open the Plugins Manager to install/uninstall plugins."""
        manager = plugins_manager.PluginsManagerWidget(self)
        manager.show()
        if manager._requirements:
            dependencyDialog = plugins_manager.DependenciesHelpDialog(
                manager._requirements)
            dependencyDialog.show()

    def show_languages(self):
        """Open the Language Manager to install/uninstall languages."""
        manager = language_manager.LanguagesManagerWidget(self)
        manager.show()

    def show_themes(self):
        """Open the Themes Manager to install/uninstall themes."""
        manager = themes_manager.ThemesManagerWidget(self)
        manager.show()

    def show_about_qt(self):
        """Show About Qt Dialog."""
        QMessageBox.aboutQt(self, translations.TR_ABOUT_QT)

    def show_about_ninja(self):
        """Show About NINJA-IDE Dialog."""
        about = about_ninja.AboutNinja(self)
        about.show()

    def show_python_detection(self):
        """Show Python detection dialog for windows."""
        #TODO: Notify the user when no python version could be found
        suggested = settings.detect_python_path()
        if suggested:
            dialog = python_detect_dialog.PythonDetectDialog(suggested, self)
            dialog.show()
Ejemplo n.º 19
0
class IDE(QMainWindow):
    """This class is like the Sauron's Ring:
    One ring to rule them all, One ring to find them,
    One ring to bring them all and in the darkness bind them.

    This Class knows all the containers, and its know by all the containers,
    but the containers don't need to know between each other, in this way we
    can keep a better api without the need to tie the behaviour between
    the widgets, and let them just consume the 'actions' they need."""

    ###############################################################################
    # SIGNALS
    #
    # goingDown()
    ###############################################################################

    __IDESERVICES = {}
    __IDECONNECTIONS = {}
    __IDESHORTCUTS = {}
    __IDEMENUSCATEGORY = {}
    __IDEMENUS = {}
    # CONNECTIONS structure:
    # ({'target': service_name, 'signal_name': string, 'slot': function_obj},)
    # On modify add: {connected: True}
    __instance = None
    __created = False

    def __init__(self, start_server=False):
        QMainWindow.__init__(self)
        self.setWindowTitle("NINJA-IDE {Ninja-IDE Is Not Just Another IDE}")
        self.setMinimumSize(700, 500)
        QToolTip.setFont(QFont(settings.FONT_FAMILY, 10))
        # Load the size and the position of the main window
        self.load_window_geometry()
        self.__project_to_open = 0

        # Editables
        self.__neditables = {}
        # Filesystem
        self.filesystem = nfilesystem.NVirtualFileSystem()

        # Start server if needed
        self.s_listener = None
        if start_server:
            self.s_listener = QLocalServer()
            self.s_listener.listen("ninja_ide")
            self.connect(self.s_listener, SIGNAL("newConnection()"), self._process_connection)

        # Profile handler
        self.profile = None
        # Opacity
        self.opacity = settings.MAX_OPACITY

        # ToolBar
        self.toolbar = QToolBar(self)
        self.toolbar.setToolTip(self.tr("Press and Drag to Move"))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.addToolBar(settings.TOOLBAR_AREA, self.toolbar)
        if settings.HIDE_TOOLBAR:
            self.toolbar.hide()
        # Notificator
        self.notification = notification.Notification(self)

        # Plugin Manager
        # services = {
        #'editor': plugin_services.MainService(),
        #'toolbar': plugin_services.ToolbarService(self.toolbar),
        ##'menuApp': plugin_services.MenuAppService(self.pluginsMenu),
        #'menuApp': plugin_services.MenuAppService(None),
        #'explorer': plugin_services.ExplorerService(),
        #'misc': plugin_services.MiscContainerService(self.misc)}
        # serviceLocator = plugin_manager.ServiceLocator(services)
        serviceLocator = plugin_manager.ServiceLocator(None)
        self.plugin_manager = plugin_manager.PluginManager(resources.PLUGINS, serviceLocator)
        self.plugin_manager.discover()
        # load all plugins!
        self.plugin_manager.load_all()

        # Tray Icon
        self.trayIcon = updates.TrayIconUpdates(self)
        self.connect(self.trayIcon, SIGNAL("closeTrayIcon()"), self._close_tray_icon)
        self.trayIcon.show()

        key = Qt.Key_1
        for i in range(10):
            if settings.IS_MAC_OS:
                short = ui_tools.TabShortcuts(QKeySequence(Qt.CTRL + Qt.ALT + key), self, i)
            else:
                short = ui_tools.TabShortcuts(QKeySequence(Qt.ALT + key), self, i)
            key += 1
            self.connect(short, SIGNAL("activated()"), self._change_tab_index)
        short = ui_tools.TabShortcuts(QKeySequence(Qt.ALT + Qt.Key_0), self, 10)
        self.connect(short, SIGNAL("activated()"), self._change_tab_index)

        # Register menu categories
        IDE.register_menu_category(translations.TR_MENU_FILE, 100)
        IDE.register_menu_category(translations.TR_MENU_EDIT, 110)
        IDE.register_menu_category(translations.TR_MENU_VIEW, 120)
        IDE.register_menu_category(translations.TR_MENU_SOURCE, 130)
        IDE.register_menu_category(translations.TR_MENU_PROJECT, 140)
        IDE.register_menu_category(translations.TR_MENU_ADDINS, 150)
        IDE.register_menu_category(translations.TR_MENU_ABOUT, 160)
        # Register General Menu Items
        ui_tools.install_shortcuts(self, actions.ACTIONS_GENERAL, self)

        self.register_service("ide", self)
        self.register_service("toolbar", self.toolbar)
        # Register signals connections
        connections = (
            {"target": "main_container", "signal_name": "fileSaved(QString)", "slot": self.show_status_message},
            {"target": "main_container", "signal_name": "currentTabChanged(QString)", "slot": self.change_window_title},
            {"target": "main_container", "signal_name": "openPreferences()", "slot": self.show_preferences},
            {"target": "main_container", "signal_name": "allTabsClosed()", "slot": self._last_tab_closed},
            {
                "target": "explorer_container",
                "signal_name": "changeWindowTitle(QString)",
                "slot": self.change_window_title,
            },
            {"target": "explorer_container", "signal_name": "projectClosed(QString)", "slot": self.close_project},
        )
        self.register_signals("ide", connections)
        # Central Widget MUST always exists
        self.central = IDE.get_service("central_container")
        self.setCentralWidget(self.central)
        # Install Services
        for service_name in self.__IDESERVICES:
            self.install_service(service_name)
        self.__created = True
        menu_bar = IDE.get_service("menu_bar")
        if menu_bar:
            menu_bar.load_menu(self)
            # These two are the same service, I think that's ok
            menu_bar.load_toolbar(self)

    @classmethod
    def get_service(cls, service_name):
        """Return the instance of a registered service."""
        return cls.__IDESERVICES.get(service_name, None)

    def get_menuitems(self):
        """Return a dictionary with the registered menu items."""
        return self.__IDEMENUS

    def get_menu_categories(self):
        """Get the registered Categories for the Application menus."""
        return self.__IDEMENUSCATEGORY

    @classmethod
    def register_service(cls, service_name, obj):
        """Register a service providing the service name and the instance."""
        cls.__IDESERVICES[service_name] = obj
        if cls.__created:
            cls.__instance.install_service(service_name)

    def install_service(self, service_name):
        """Activate the registered service."""
        obj = self.__IDESERVICES.get(service_name, None)
        func = getattr(obj, "install", None)
        if isinstance(func, collections.Callable):
            func()
        self._connect_signals()

    def place_me_on(self, name, obj, region="central", top=False):
        """Place a widget in some of the areas in the IDE.
        @name: id to access to that widget later if needed.
        @obj: the instance of the widget to be placed.
        @region: the area where to put the widget [central, lateral]
        @top: place the widget as the first item in the split."""
        self.central.add_to_region(name, obj, region, top)

    @classmethod
    def register_signals(cls, service_name, connections):
        """Register all the signals that a particular service wants to be
        attached of.
        @service_name: id of the service
        @connections: list of dictionaries for the connection with:
            - 'target': 'the_other_service_name',
            - 'signal_name': 'name of the signal in the other service',
            - 'slot': function object in this service"""
        cls.__IDECONNECTIONS[service_name] = connections
        if cls.__created:
            cls.__instance._connect_signals()

    def _connect_signals(self):
        """Connect the signals between the different services."""
        for service_name in self.__IDECONNECTIONS:
            connections = self.__IDECONNECTIONS[service_name]
            for connection in connections:
                if connection.get("connected", False):
                    continue
                target = self.__IDESERVICES.get(connection["target"], None)
                slot = connection["slot"]
                signal_name = connection["signal_name"]
                if target and isinstance(slot, collections.Callable):
                    self.connect(target, SIGNAL(signal_name), slot)
                    connection["connected"] = True

    @classmethod
    def register_shortcut(cls, shortcut_name, shortcut, action=None):
        """Register a shortcut and action."""
        cls.__IDESHORTCUTS[shortcut_name] = (shortcut, action)

    @classmethod
    def register_menuitem(cls, menu_action, section, weight):
        """Register a QAction or QMenu in the IDE to be loaded later in the
        menubar using the section(string) to define where is going to be
        contained, and the weight define the order where is going to be
        placed.
        @menu_action: QAction or QMenu
        @section: String (name)
        @weight: int"""
        cls.__IDEMENUS[menu_action] = (section, weight)

    @classmethod
    def register_menu_category(cls, category_name, weight):
        """Register a Menu Category to be created with the proper weight.
        @category_name: string
        @weight: int"""
        cls.__IDEMENUSCATEGORY[category_name] = weight

    @classmethod
    def update_shortcut(cls, shortcut_name):
        """Update all the shortcuts of the application."""
        short = resources.get_shortcut
        shortcut, action = cls.__IDESHORTCUTS.get(shortcut_name)
        if shortcut:
            shortcut.setKey(short(shortcut_name))
        if action:
            action.setShortcut(short(shortcut_name))

    def get_or_create_editable(self, filename):
        nfile = self.filesystem.get_file(nfile_path=filename)
        editable = self.__neditables.get(nfile)
        if editable is None:
            editable = neditable.NEditable(nfile)
            self.__neditables[nfile] = editable
        return editable

    def get_project_for_file(self, filename):
        project = None
        if filename:
            project = self.filesystem.get_project_for_file(filename)
        return project

    def create_project(self, path):
        nproj = nproject.NProject(path)
        self.filesystem.open_project(nproj)
        return nproj

    def close_project(self, project_path):
        self.filesystem.close_project(project_path)

    def get_projects(self):
        return self.filesystem.get_projects()

    def get_current_project(self):
        current_project = None
        projects = self.filesystem.get_projects()
        for project in projects:
            if projects[project].is_current:
                current_project = projects[project]
                break
        return current_project

    def select_current(self, widget):
        """Show the widget with a 4px lightblue border line."""
        self.setProperty("highlight", True)
        self.style().unpolish(self)
        self.style().polish(self)

    def unselect_current(self, widget):
        """Remove the 4px lightblue border line from the widget."""
        self.setProperty("highlight", False)
        self.style().unpolish(widget)
        self.style().polish(widget)

    def get_opened_projects(self):
        return self.__projects

    def _close_tray_icon(self):
        """Close the System Tray Icon."""
        self.trayIcon.hide()
        self.trayIcon.deleteLater()

    def _change_tab_index(self):
        """Change the tabs of the current TabWidget using alt+numbers."""
        widget = QApplication.focusWidget()
        shortcut_index = getattr(widget, "shortcut_index", None)
        if shortcut_index:
            obj = self.sender()
            shortcut_index(obj.index)

    def switch_focus(self):
        """Switch the current keyboard focus to the next widget."""
        widget = QApplication.focusWidget()
        main_container = IDE.get_service("main_container")
        tools_dock = IDE.get_service("tools_dock")
        explorer_container = IDE.get_service("explorer_container")
        if widget and main_container and tools_dock and explorer_container:
            if widget in (main_container.actualTab, main_container.actualTab.currentWidget()):
                explorer_container.currentWidget().setFocus()
            elif widget in (explorer_container, explorer_container.currentWidget()):
                if tools_dock.isVisible():
                    tools_dock.stack.currentWidget().setFocus()
                else:
                    main_container.actualTab.currentWidget().setFocus()
            elif widget.parent() is tools_dock.stack:
                main_container.actualTab.currentWidget().setFocus()

    def _process_connection(self):
        """Read the ipc input from another instance of ninja."""
        connection = self.s_listener.nextPendingConnection()
        connection.waitForReadyRead()
        data = connection.readAll()
        connection.close()
        if data:
            files, projects = str(data).split(ipc.project_delimiter, 1)
            files = [(x.split(":")[0], int(x.split(":")[1])) for x in files.split(ipc.file_delimiter)]
            projects = projects.split(ipc.project_delimiter)
            self.load_session_files_projects(files, [], projects, None)

    def fullscreen_mode(self):
        """Change to fullscreen mode."""
        if self.isFullScreen():
            self.showMaximized()
        else:
            self.showFullScreen()

    def change_toolbar_visibility(self):
        """Switch the toolbar visibility"""
        if self.toolbar.isVisible():
            self.toolbar.hide()
        else:
            self.toolbar.show()

    def load_external_plugins(self, paths):
        """Load external plugins, the ones added to ninja throw the cmd."""
        for path in paths:
            self.plugin_manager.add_plugin_dir(path)
        # load all plugins!
        self.plugin_manager.discover()
        self.plugin_manager.load_all()

    def _last_tab_closed(self):
        """
        Called when the last tasb is closed
        """
        self.explorer.cleanup_tabs()

    def show_preferences(self):
        """Open the Preferences Dialog."""
        pref = preferences.PreferencesWidget(self)
        pref.show()

    def load_session_files_projects(self, filesTab1, filesTab2, projects, current_file, recent_files=None):
        """Load the files and projects from previous session."""
        self.__project_to_open = len(projects)
        explorer = IDE.get_service("explorer_container")
        main_container = IDE.get_service("main_container")
        if explorer and main_container:
            self.connect(explorer, SIGNAL("projectOpened(QString)"), self._set_editors_project_data)
            explorer.open_session_projects(projects, notIDEStart=False)
            main_container.open_files(filesTab1, notIDEStart=False)
            main_container.open_files(filesTab2, mainTab=False, notIDEStart=False)
            if current_file:
                main_container.open_file(current_file, notStart=False)
            # if recent_files is not None:
            # menu_file = IDE.get_service('menu_file')
            # menu_file.update_recent_files(recent_files)

    # def _set_editors_project_data(self):
    # self.__project_to_open -= 1
    # if self.__project_to_open == 0:
    # self.disconnect(self.explorer, SIGNAL("projectOpened(QString)"),
    # self._set_editors_project_data)
    # self.mainContainer.update_editor_project()

    # def open_file(self, filename):
    # if filename:
    # self.mainContainer.open_file(filename)

    # def open_project(self, project):
    # if project:
    # self.actions.open_project(project)

    def __get_profile(self):
        return self.profile

    def __set_profile(self, profileName):
        self.profile = profileName
        if self.profile is not None:
            self.setWindowTitle("NINJA-IDE (PROFILE: %s)" % self.profile)
        else:
            self.setWindowTitle("NINJA-IDE {Ninja-IDE Is Not Just Another IDE}")

    Profile = property(__get_profile, __set_profile)

    def change_window_title(self, title):
        """Change the title of the Application."""
        if self.profile is None:
            self.setWindowTitle("NINJA-IDE - %s" % title)
        else:
            self.setWindowTitle("NINJA-IDE (PROFILE: %s) - %s" % (self.profile, title))

    def wheelEvent(self, event):
        """Change the opacity of the application."""
        if event.modifiers() == Qt.ShiftModifier:
            if event.delta() == 120 and self.opacity < settings.MAX_OPACITY:
                self.opacity += 0.1
            elif event.delta() == -120 and self.opacity > settings.MIN_OPACITY:
                self.opacity -= 0.1
            self.setWindowOpacity(self.opacity)
            event.ignore()
        else:
            QMainWindow.wheelEvent(self, event)

    def save_settings(self):
        """Save the settings before the application is closed with QSettings.

        Info saved: Tabs and projects opened, windows state(size and position).
        """
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        editor_widget = self.mainContainer.get_actual_editor()
        current_file = ""
        if editor_widget is not None:
            current_file = editor_widget.ID
        if qsettings.value("preferences/general/loadFiles", True, type=bool):
            openedFiles = self.mainContainer.get_opened_documents()
            projects_obj = self.get_opened_projects()
            projects = [p.path for p in projects_obj]
            qsettings.setValue("openFiles/projects", projects)
            if len(openedFiles) > 0:
                qsettings.setValue("openFiles/mainTab", openedFiles[0])
            if len(openedFiles) == 2:
                qsettings.setValue("openFiles/secondaryTab", openedFiles[1])
            qsettings.setValue("openFiles/currentFile", current_file)
            qsettings.setValue("openFiles/recentFiles", self.mainContainer._tabMain.get_recent_files_list())
        qsettings.setValue("preferences/editor/bookmarks", settings.BOOKMARKS)
        qsettings.setValue("preferences/editor/breakpoints", settings.BREAKPOINTS)
        qsettings.setValue("preferences/general/toolbarArea", self.toolBarArea(self.toolbar))
        # Save if the windows state is maximixed
        if self.isMaximized():
            qsettings.setValue("window/maximized", True)
        else:
            qsettings.setValue("window/maximized", False)
            # Save the size and position of the mainwindow
            qsettings.setValue("window/size", self.size())
            qsettings.setValue("window/pos", self.pos())
        # Save the size of de splitters
        qsettings.setValue("window/central/baseSize", self.central.get_area_sizes())
        qsettings.setValue("window/central/insideSize", self.central.get_main_sizes())
        # Save the toolbar visibility
        if not self.toolbar.isVisible() and self.menuBar().isVisible():
            qsettings.setValue("window/hide_toolbar", True)
        else:
            qsettings.setValue("window/hide_toolbar", False)
        # Save Misc state
        qsettings.setValue("window/show_region1", self.misc.isVisible())
        # Save Profiles
        if self.profile is not None:
            self.actions.save_profile(self.profile)
        else:
            qsettings.setValue("ide/profiles", settings.PROFILES)

    def create_profile(self):
        """Create a profile binding files and projects to a key."""
        profileInfo = QInputDialog.getText(
            None,
            self.tr("Create Profile"),
            self.tr("The Current Files and Projects will " "be associated to this profile.\n" "Profile Name:"),
        )
        if profileInfo[1]:
            profileName = profileInfo[0]
            if not profileName or profileName in settings.PROFILES:
                QMessageBox.information(
                    self, self.tr("Profile Name Invalid"), self.tr("The Profile name is invalid or already exists.")
                )
                return
            self.save_profile(profileName)
            return profileName

    def save_profile(self, profileName):
        """Save the updates from a profile."""
        ide = IDE.get_service("ide")
        main_container = IDE.get_service("main_container")
        if main_container:
            projects_obj = ide.get_opened_projects()
            projects = [p.path for p in projects_obj]
            files = main_container.get_opened_documents()
            files = files[0] + files[1]
            settings.PROFILES[profileName] = [files, projects]
            qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
            qsettings.setValue("ide/profiles", settings.PROFILES)

    def activate_profile(self):
        """Show the Profile Manager dialog."""
        profilesLoader = ui_tools.ProfilesLoader(
            self._load_profile_data, self.create_profile, self.save_profile, settings.PROFILES, self.ide
        )
        profilesLoader.show()

    def deactivate_profile(self):
        """Close the Profile Session."""
        self.Profile = None

    def _load_profile_data(self, key):
        """Activate the selected profile, closing the current files/projects"""
        explorer = IDE.get_service("explorer_container")
        main_container = IDE.get_service("main_container")
        if explorer and main_container:
            explorer.close_opened_projects()
            main_container.open_files(settings.PROFILES[key][0])
            explorer.open_session_projects(settings.PROFILES[key][1])

    def load_window_geometry(self):
        """Load from QSettings the window size of de Ninja IDE"""
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        if qsettings.value("window/maximized", True, type=bool):
            self.setWindowState(Qt.WindowMaximized)
        else:
            self.resize(qsettings.value("window/size", QSizeF(800, 600).toSize(), type="QSize"))
            self.move(qsettings.value("window/pos", QPointF(100, 100).toPoint(), type="QPoint"))

    def closeEvent(self, event):
        """Saves some global settings before closing."""
        if self.s_listener:
            self.s_listener.close()
        # if (settings.CONFIRM_EXIT and
        # self.mainContainer.check_for_unsaved_tabs()):
        # unsaved_files = self.mainContainer.get_unsaved_files()
        # txt = '\n'.join(unsaved_files)
        # val = QMessageBox.question(self,
        # self.tr("Some changes were not saved"),
        # (self.tr("%s\n\nDo you want to save them?") % txt),
        # QMessageBox.Yes, QMessageBox.No, QMessageBox.Cancel)
        # if val == QMessageBox.Yes:
        ##Saves all open files
        # main_container = IDE.get_service('main_container')
        # if main_container:
        # main_container.save_all()
        # if val == QMessageBox.Cancel:
        # event.ignore()
        # self.emit(SIGNAL("goingDown()"))
        # self.save_settings()
        # completion_daemon.shutdown_daemon()
        ##close python documentation server (if running)
        # self.mainContainer.close_python_doc()
        ##Shutdown PluginManager
        self.plugin_manager.shutdown()
        super(IDE, self).closeEvent(event)

    def notify_plugin_errors(self):
        # TODO: Check if the Plugin Error dialog can be improved
        errors = self.plugin_manager.errors
        if errors:
            plugin_error_dialog = traceback_widget.PluginErrorDialog()
            for err_tuple in errors:
                plugin_error_dialog.add_traceback(err_tuple[0], err_tuple[1])
            # show the dialog
            plugin_error_dialog.exec_()

    def show_status_message(self, message, duration=3000):
        """Show status message."""
        self.notification.set_message(message, duration)
        self.notification.show()

    def show_manager(self):
        """Open the Plugins Manager to install/uninstall plugins."""
        manager = plugins_manager.PluginsManagerWidget(self)
        manager.show()
        if manager._requirements:
            dependencyDialog = plugins_manager.DependenciesHelpDialog(manager._requirements)
            dependencyDialog.show()

    def show_languages(self):
        """Open the Language Manager to install/uninstall languages."""
        manager = language_manager.LanguagesManagerWidget(self)
        manager.show()

    def show_themes(self):
        """Open the Themes Manager to install/uninstall themes."""
        manager = themes_manager.ThemesManagerWidget(self)
        manager.show()

    def show_about_qt(self):
        """Show About Qt Dialog."""
        QMessageBox.aboutQt(self, translations.TR_ABOUT_QT)

    def show_about_ninja(self):
        """Show About NINJA-IDE Dialog."""
        about = about_ninja.AboutNinja(self)
        about.show()

    def show_python_detection(self):
        """Show Python detection dialog for windows."""
        # TODO: Notify the user when no python version could be found
        suggested = settings.detect_python_path()
        if suggested:
            dialog = python_detect_dialog.PythonDetectDialog(suggested, self)
            dialog.show()
Ejemplo n.º 20
0
class SocketServerThread(QThread):
    def __init__(self, parent=None, readerThread=None):
        QThread.__init__(self, parent)

        self.readerThread = readerThread;
        self.connected = False

        self.timer = QTimer()
        
        self.server = QLocalServer()
        QLocalServer.removeServer('doorbotgui')
        
        if not self.server.listen('doorbotgui'):
            print(self.server.errorString())
            return

        botlog.info('SocketServerThread Initialized.')
        
    def __del__(self):
        botlog.info('SocketServer Thread Deletion')

    def onTimer(self):
        if self.connected:
            self.sendCurrentTime()
            self.sendCurrentSchedule()
        
    def sendPacket(self, pkt):
        if self.connected:
            try:
                self.client.write(json.dumps(pkt) + '\n')
                self.client.flush()
            except:
                print('could not sendPacket')

    def sendReadStatus(self):
        pkt = {'cmd':'readstatus', 'status':str(self.readerThread.status)}
        self.sendPacket(pkt)

    def sendAccess(self, allowed, memberData):
        pkt = {'cmd':'access', 'result':allowed, 'member':memberData}
        self.sendPacket(pkt)

    def sendCurrentTime(self):
        pkt = {'cmd':'time', 'time':datetime.now().strftime("%A, %d %B %Y %H:%M:%S")}
        self.sendPacket(pkt)

    def sendCurrentSchedule(self):
        pkt = {'cmd':'schedule', 'description':qsetup.schedule.scheduleDesc()}
        self.sendPacket(pkt)
        
    def onStatusChange(self, status):
        self.sendReadStatus()

    def onAccess(self, allowed, memberData):
        self.sendAccess(allowed, memberData)
        
    def onConnect(self):
        botlog.info('New connection to SocketServer')

        try:
            self.client = self.server.nextPendingConnection()
            self.client.disconnected.connect(self.onDisconnect)

        except:
            botlog.error('exception creating client')

        self.connected = True
            
        self.sendReadStatus()
        self.sendCurrentSchedule()

    def onDisconnect(self):
        self.connected = False
        self.client.deleteLater()
        botlog.info('SocketServer disconnected')
        
    def run(self):
        botlog.info('SocketServer Thread Running')

        if self.readerThread:
            self.readerThread.signalStatusChange.connect(self.onStatusChange)
            self.readerThread.signalAccess.connect(self.onAccess)
        
        self.server.newConnection.connect(self.onConnect)

        self.timer.timeout.connect(self.onTimer)
        self.timer.start(1000)
        
        self.exec()
        botlog.info('SocketServerThread Stopped.')
Ejemplo n.º 21
0
class __IDE(QMainWindow):
###############################################################################
# SIGNALS
#
# goingDown()
###############################################################################

    def __init__(self, start_server=False):
        QMainWindow.__init__(self)
        self.setWindowTitle('AL\'EXA-IDE {Al\'exa-IDE Is Not Just Another IDE}')
        self.setMinimumSize(700, 500)
        #Load the size and the position of the main window
        self.load_window_geometry()
        self.__project_to_open = 0

        #Start server if needed
        self.s_listener = None
        if start_server:
            self.s_listener = QLocalServer()
            self.s_listener.listen("ninja_ide")
            self.connect(self.s_listener, SIGNAL("newConnection()"),
                self._process_connection)

        #Profile handler
        self.profile = None
        #Opacity
        self.opacity = settings.MAX_OPACITY

        #Define Actions object before the UI
        self.actions = actions.Actions()
        #StatusBar
        self.status = status_bar.StatusBar(self)
        self.status.hide()
        self.setStatusBar(self.status)
        #Main Widget - Create first than everything else
        self.central = central_widget.CentralWidget(self)
        self.load_ui(self.central)
        self.setCentralWidget(self.central)

        #ToolBar
        self.toolbar = QToolBar(self)
        self.toolbar.setToolTip(self.tr("Press and Drag to Move"))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.addToolBar(settings.TOOLBAR_AREA, self.toolbar)
        if settings.HIDE_TOOLBAR:
            self.toolbar.hide()

        #Install Shortcuts after the UI has been initialized
        self.actions.install_shortcuts(self)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
            self.actions.update_explorer)

        #Menu
        menubar = self.menuBar()
        file_ = menubar.addMenu(self.tr("&File"))
        edit = menubar.addMenu(self.tr("&Edit"))
        view = menubar.addMenu(self.tr("&View"))
        source = menubar.addMenu(self.tr("&Source"))
        project = menubar.addMenu(self.tr("&Project"))
        self.pluginsMenu = menubar.addMenu(self.tr("&Addins"))
        about = menubar.addMenu(self.tr("Abou&t"))

        #The order of the icons in the toolbar is defined by this calls
        self._menuFile = menu_file.MenuFile(file_, self.toolbar, self)
        self._menuView = menu_view.MenuView(view, self.toolbar, self)
        self._menuEdit = menu_edit.MenuEdit(edit, self.toolbar)
        self._menuSource = menu_source.MenuSource(source)
        self._menuProject = menu_project.MenuProject(project, self.toolbar)
        self._menuPlugins = menu_plugins.MenuPlugins(self.pluginsMenu)
        self._menuAbout = menu_about.MenuAbout(about)

        self.load_toolbar()

        #Plugin Manager
        services = {
            'editor': plugin_services.MainService(),
            'toolbar': plugin_services.ToolbarService(self.toolbar),
            'menuApp': plugin_services.MenuAppService(self.pluginsMenu),
            'explorer': plugin_services.ExplorerService(),
            'misc': plugin_services.MiscContainerService(self.misc)}
        serviceLocator = plugin_manager.ServiceLocator(services)
        self.plugin_manager = plugin_manager.PluginManager(resources.PLUGINS,
            serviceLocator)
        self.plugin_manager.discover()
        #load all plugins!
        self.plugin_manager.load_all()

        #Tray Icon
        self.trayIcon = updates.TrayIconUpdates(self)
        self.trayIcon.show()

        self.connect(self._menuFile, SIGNAL("openFile(QString)"),
            self.mainContainer.open_file)
        self.connect(self.mainContainer, SIGNAL("fileSaved(QString)"),
            self.show_status_message)
        self.connect(self.mainContainer,
            SIGNAL("recentTabsModified(QStringList)"),
            self._menuFile.update_recent_files)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
            self.actions.update_migration_tips)
        self.connect(self.mainContainer, SIGNAL("updateFileMetadata(QString)"),
            self.actions.update_migration_tips)
        self.connect(self.mainContainer, SIGNAL("migrationAnalyzed()"),
            self.actions.update_migration_tips)

    def _process_connection(self):
        connection = self.s_listener.nextPendingConnection()
        connection.waitForReadyRead()
        data = connection.readAll()
        connection.close()
        if data:
            files, projects = str(data).split(ipc.project_delimiter, 1)
            files = [(x.split(':')[0], int(x.split(':')[1]))
                for x in files.split(ipc.file_delimiter)]
            projects = projects.split(ipc.project_delimiter)
            self.load_session_files_projects(files, [], projects, None)

    def load_toolbar(self):
        self.toolbar.clear()
        toolbar_items = {}
        toolbar_items.update(self._menuFile.toolbar_items)
        toolbar_items.update(self._menuView.toolbar_items)
        toolbar_items.update(self._menuEdit.toolbar_items)
        toolbar_items.update(self._menuSource.toolbar_items)
        toolbar_items.update(self._menuProject.toolbar_items)

        for item in settings.TOOLBAR_ITEMS:
            if item == 'separator':
                self.toolbar.addSeparator()
            else:
                tool_item = toolbar_items.get(item, None)
                if tool_item is not None:
                    self.toolbar.addAction(tool_item)
        #load action added by plugins, This is a special case when reload
        #the toolbar after save the preferences widget
        for toolbar_action in settings.get_toolbar_item_for_plugins():
            self.toolbar.addAction(toolbar_action)

    def load_external_plugins(self, paths):
        for path in paths:
            self.plugin_manager.add_plugin_dir(path)
        #load all plugins!
        self.plugin_manager.discover()
        self.plugin_manager.load_all()

    def show_status_message(self, message):
        self.status.showMessage(message, 2000)

    def load_ui(self, centralWidget):
        #Set Application Font for ToolTips
        QToolTip.setFont(QFont(settings.FONT_FAMILY, 10))
        #Create Main Container to manage Tabs
        self.mainContainer = main_container.MainContainer(self)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
            self.change_window_title)
        self.connect(self.mainContainer,
            SIGNAL("locateFunction(QString, QString, bool)"),
            self.actions.locate_function)
        self.connect(self.mainContainer,
            SIGNAL("navigateCode(bool, int)"),
            self.actions.navigate_code_history)
        self.connect(self.mainContainer,
            SIGNAL("addBackItemNavigation()"),
            self.actions.add_back_item_navigation)
        self.connect(self.mainContainer, SIGNAL("updateFileMetadata()"),
            self.actions.update_explorer)
        self.connect(self.mainContainer, SIGNAL("updateLocator(QString)"),
            self.actions.update_explorer)
        self.connect(self.mainContainer, SIGNAL("openPreferences()"),
            self._show_preferences)
        self.connect(self.mainContainer, SIGNAL("dontOpenStartPage()"),
            self._dont_show_start_page_again)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
            self.status.handle_tab_changed)
        # When close the last tab cleanup
        self.connect(self.mainContainer, SIGNAL("allTabsClosed()"),
            self._last_tab_closed)
        # Update symbols
        self.connect(self.mainContainer, SIGNAL("updateLocator(QString)"),
            self.status.explore_file_code)
        #Create Explorer Panel
        self.explorer = explorer_container.ExplorerContainer(self)
        self.connect(self.central, SIGNAL("splitterCentralRotated()"),
            self.explorer.rotate_tab_position)
        self.connect(self.explorer, SIGNAL("updateLocator()"),
            self.status.explore_code)
        self.connect(self.explorer, SIGNAL("goToDefinition(int)"),
            self.actions.editor_go_to_line)
        self.connect(self.explorer, SIGNAL("projectClosed(QString)"),
            self.actions.close_files_from_project)
        #Create Misc Bottom Container
        self.misc = misc_container.MiscContainer(self)
        self.connect(self.mainContainer, SIGNAL("findOcurrences(QString)"),
            self.misc.show_find_occurrences)

        centralWidget.insert_central_container(self.mainContainer)
        centralWidget.insert_lateral_container(self.explorer)
        centralWidget.insert_bottom_container(self.misc)
        if self.explorer.count() == 0:
            centralWidget.change_explorer_visibility(force_hide=True)
        self.connect(self.mainContainer,
            SIGNAL("cursorPositionChange(int, int)"),
            self.central.lateralPanel.update_line_col)
        # TODO: Change current symbol on move
        #self.connect(self.mainContainer,
            #SIGNAL("cursorPositionChange(int, int)"),
            #self.explorer.update_current_symbol)
        self.connect(self.mainContainer, SIGNAL("enabledFollowMode(bool)"),
            self.central.enable_follow_mode_scrollbar)

        if settings.SHOW_START_PAGE:
            self.mainContainer.show_start_page()

    def _last_tab_closed(self):
        """
        Called when the last tasb is closed
        """
        self.explorer.cleanup_tabs()

    def _show_preferences(self):
        pref = preferences.PreferencesWidget(self.mainContainer)
        pref.show()

    def _dont_show_start_page_again(self):
        settings.SHOW_START_PAGE = False
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        qsettings.beginGroup('preferences')
        qsettings.beginGroup('general')
        qsettings.setValue('showStartPage', settings.SHOW_START_PAGE)
        qsettings.endGroup()
        qsettings.endGroup()
        self.mainContainer.actualTab.close_tab()

    def load_session_files_projects(self, filesTab1, filesTab2, projects,
        current_file, recent_files=None):
        self.__project_to_open = len(projects)
        self.connect(self.explorer, SIGNAL("projectOpened(QString)"),
            self._set_editors_project_data)
        self.explorer.open_session_projects(projects, notIDEStart=False)
        self.mainContainer.open_files(filesTab1, notIDEStart=False)
        self.mainContainer.open_files(filesTab2, mainTab=False,
            notIDEStart=False)
        if current_file:
            self.mainContainer.open_file(current_file, notStart=False)
        if recent_files is not None:
            self._menuFile.update_recent_files(recent_files)

    def _set_editors_project_data(self):
        self.__project_to_open -= 1
        if self.__project_to_open == 0:
            self.disconnect(self.explorer, SIGNAL("projectOpened(QString)"),
                self._set_editors_project_data)
            self.mainContainer.update_editor_project()

    def open_file(self, filename):
        if filename:
            self.mainContainer.open_file(filename)

    def open_project(self, project):
        if project:
            self.actions.open_project(project)

    def __get_profile(self):
        return self.profile

    def __set_profile(self, profileName):
        self.profile = profileName
        if self.profile is not None:
            self.setWindowTitle('AL\'EXA-IDE (PROFILE: %s)' % self.profile)
        else:
            self.setWindowTitle(
                'AL\'EXA-IDE {Al\'exa-IDE Is Not Just Another IDE}')

    Profile = property(__get_profile, __set_profile)

    def change_window_title(self, title):
        if self.profile is None:
            self.setWindowTitle('AL\'EXA-IDE - %s' % title)
        else:
            self.setWindowTitle('AL\'EXA-IDE (PROFILE: %s) - %s' % (
                self.profile, title))
        currentEditor = self.mainContainer.get_actual_editor()
        if currentEditor is not None:
            line = currentEditor.textCursor().blockNumber() + 1
            col = currentEditor.textCursor().columnNumber()
            self.central.lateralPanel.update_line_col(line, col)

    def wheelEvent(self, event):
        if event.modifiers() == Qt.ShiftModifier:
            if event.delta() == 120 and self.opacity < settings.MAX_OPACITY:
                self.opacity += 0.1
            elif event.delta() == -120 and self.opacity > settings.MIN_OPACITY:
                self.opacity -= 0.1
            self.setWindowOpacity(self.opacity)
            event.ignore()
        else:
            QMainWindow.wheelEvent(self, event)

    def save_settings(self):
        """Save the settings before the application is closed with QSettings.

        Info saved: Tabs and projects opened, windows state(size and position).
        """
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        editor_widget = self.mainContainer.get_actual_editor()
        current_file = ''
        if editor_widget is not None:
            current_file = editor_widget.ID
        if qsettings.value('preferences/general/loadFiles', True, type=bool):
            openedFiles = self.mainContainer.get_opened_documents()
            projects_obj = self.explorer.get_opened_projects()
            projects = [p.path for p in projects_obj]
            qsettings.setValue('openFiles/projects',
                projects)
            if len(openedFiles) > 0:
                qsettings.setValue('openFiles/mainTab', openedFiles[0])
            if len(openedFiles) == 2:
                qsettings.setValue('openFiles/secondaryTab', openedFiles[1])
            qsettings.setValue('openFiles/currentFile', current_file)
            qsettings.setValue('openFiles/recentFiles',
                self.mainContainer._tabMain.get_recent_files_list())
        qsettings.setValue('preferences/editor/bookmarks', settings.BOOKMARKS)
        qsettings.setValue('preferences/editor/breakpoints',
            settings.BREAKPOINTS)
        qsettings.setValue('preferences/general/toolbarArea',
            self.toolBarArea(self.toolbar))
        #Save if the windows state is maximixed
        if(self.isMaximized()):
            qsettings.setValue("window/maximized", True)
        else:
            qsettings.setValue("window/maximized", False)
            #Save the size and position of the mainwindow
            qsettings.setValue("window/size", self.size())
            qsettings.setValue("window/pos", self.pos())
        #Save the size of de splitters
        qsettings.setValue("window/central/areaSize",
            self.central.get_area_sizes())
        qsettings.setValue("window/central/mainSize",
            self.central.get_main_sizes())
        #Save the toolbar visibility
        if not self.toolbar.isVisible() and self.menuBar().isVisible():
            qsettings.setValue("window/hide_toolbar", True)
        else:
            qsettings.setValue("window/hide_toolbar", False)
        #Save Misc state
        qsettings.setValue("window/show_misc", self.misc.isVisible())
        #Save Profiles
        if self.profile is not None:
            self.actions.save_profile(self.profile)
        else:
            qsettings.setValue('ide/profiles', settings.PROFILES)

    def load_window_geometry(self):
        """Load from QSettings the window size of de Ninja IDE"""
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        if qsettings.value("window/maximized", True, type=bool):
            self.setWindowState(Qt.WindowMaximized)
        else:
            self.resize(qsettings.value("window/size",
                QSizeF(800, 600).toSize(), type='QSize'))
            self.move(qsettings.value("window/pos",
                QPointF(100, 100).toPoint(), type='QPoint'))

    def CloseHideAllWindow(self, close=True):
        if sys.platform == 'win32':
            import win32gui
            import win32con
            import re

            toplist, winlist = [], []

            def enum_callback(hwnd, results):
                winlist.append((hwnd, win32gui.GetWindowText(hwnd)))

            win32gui.EnumWindows(enum_callback, toplist)

            #^(?!.*details\.cfm).*selector=size.*$
            #window = [(hwnd, curTitle) for hwnd, curTitle in winlist if re.match("al.*exa.*(tool|nagios utilities|mouse and keyboard).*", curTitle, re.DOTALL | re.IGNORECASE) != None and win32gui.IsWindowVisible(hwnd) != 0]
            windows = [(hwnd, curTitle) for hwnd, curTitle in winlist]

            # just grab the hwnd for first window matching title
            #print "toplist", top
            if len(windows) > 0:
                toplist, winlist = [], []
                #print windows

                for window in windows:
                    try:
                        #if openedWindow[0].lower() == 'Al\'exa tools':
                        title = window[1]
                        if 'al\'exa tools' == title.lower() or 'al\'exa - nagios utilities' == title.lower() or 'al\'exa - mouse and keyboard' == title.lower() or 'al\'exa - windows and region' == title.lower() or 'al\'exa - process utilities' == title.lower() or 'al\'exa - e-mail' == title.lower():
                            if close is True:
                                win32gui.PostMessage(window[0], win32con.WM_CLOSE, 0, 0)
                            else:
                                win32gui.ShowWindow(window[0], 0)
                    except:
                        continue

    def closeEvent(self, event):

        if self.s_listener:
            self.s_listener.close()
        if (settings.CONFIRM_EXIT and
                self.mainContainer.check_for_unsaved_tabs()):
            unsaved_files = self.mainContainer.get_unsaved_files()
            txt = '\n'.join(unsaved_files)

            self.CloseHideAllWindow(False)
            val = QMessageBox.question(self,
                self.tr("Some changes were not saved"),
                (self.tr("%s\n\nDo you want to save them?") % txt),
                QMessageBox.Yes, QMessageBox.No, QMessageBox.Cancel)

            '''
            msgBox = QMessageBox()
            msgBox.setWindowTitle("QMessageBox Always On Top")
            msgBox.setText("This is an always-on-top QMessageBox!")
            msgBox.setWindowFlags(Qt.WindowStaysOnTopHint)
            msgBox.show()
            '''

            #val.setWindowFlags(Qt.WindowStaysOnTopHint)

            if val == QMessageBox.Yes:
                #Saves all open files
                self.mainContainer.save_all()
            if val == QMessageBox.Cancel:
                event.ignore()
                return
        self.emit(SIGNAL("goingDown()"))
        self.save_settings()
        completion_daemon.shutdown_daemon()
        #close python documentation server (if running)
        self.mainContainer.close_python_doc()
        #Shutdown PluginManager
        self.plugin_manager.shutdown()
        self.CloseHideAllWindow(True)

    def notify_plugin_errors(self):
        errors = self.plugin_manager.errors
        if errors:
            plugin_error_dialog = traceback_widget.PluginErrorDialog()
            for err_tuple in errors:
                plugin_error_dialog.add_traceback(err_tuple[0], err_tuple[1])
            #show the dialog
            plugin_error_dialog.exec_()

    def show_python_detection(self):
        suggested = settings.detect_python_path()
        if suggested:
            dialog = python_detect_dialog.PythonDetectDialog(suggested, self)
            dialog.show()
Ejemplo n.º 22
0
class GUIServer():
    
    def __init__(self):
        self.heartbeats = 0
        self.connected = False
        
        self.timer = QTimer()
        self.timer.timeout.connect(self.tick)
        self.timer.start(500)
        
        self.server = QLocalServer()
        QLocalServer.removeServer('doorbotgui')
        
        if not self.server.listen('doorbotgui'):
            print(self.server.errorString())
            return

        self.server.newConnection.connect(self.handleConnection)
        
        super(GUIServer, self).__init__()

    def handleDisconnect(self):
        self.connected = False
        self.client.deleteLater()
        
    def handleConnection(self):
        self.client = self.server.nextPendingConnection()
        self.client.disconnected.connect(self.handleDisconnect)

        self.heartbeats = 0
        self.connected = True

        self.sendPacket({'cmd':'schedule', 'description':'Hobbyist and Pro Allowed Until 10PM'})
        self.sendPacket({'cmd':'bulletin', 'source':'testmsg1.html'})
        self.sendPacket({'cmd':'readstatus', 'status':'Please scan your RFID below.'})

        
    def sendPacket(self, pkt):
        if self.connected:
            try:
                self.client.write(json.dumps(pkt) + '\n')
                self.client.flush()
            except:
                print('could not sendPacket')
                
        
    def tick(self):

        if self.connected:
            self.heartbeats = self.heartbeats + 1

            if self.heartbeats % 10 == 0:
                heartbeat = {'cmd':'heartbeat', 'count': self.heartbeats}
                self.sendPacket(heartbeat)

                if self.heartbeats % 20 == 0:
                    self.sendPacket({'cmd':'bulletin', 'source':'testmsg1.html'})
                else:
                    self.sendPacket({'cmd':'bulletin', 'source':'testmsg2.html'})
    

            if self.heartbeats % 22 == 0:
                access = {'cmd':'access', 'result':'allowed',
                          'member':{"tagid": "12345", "member": "Johnathan.Smith", "warning": "", "plan": "pro", "allowed": "allowed", "nickname": "Johnathan Smith"}
                }
                self.sendPacket(access)
                
            if self.heartbeats % 33 == 0:
                access = {'cmd':'access', 'result':'allowed',
                          'member':{"tagid": "12345", "member": "Bill.Jones", "warning": "Your membership expired (2016-01-15T00:04:25Z) and you are in a grace period for 14 days.  Please update your payment information or you will lose access.", "plan": "hobbyist", "allowed": "allowed", "nickname": "Bill Jones"}
                }
                self.sendPacket(access)

            if self.heartbeats % 55 == 0:
                access = {'cmd':'access', 'result':'denied',
                          'member':{"tagid": "abcde", "member": "Al.Johnson", "warning": "Your membership expired (2012-07-02T00:04:25Z) and the grace period for access has ended. Contact [email protected] with any questions.", "plan": "hobbyist", "allowed": "denied", "nickname": None}
                      }
                self.sendPacket(access)

            if self.heartbeats % 77 == 0:
                access = {'cmd':'access', 'result':'denied',
                              'member':{"tagid": "123abc", "member": "Michael.Michaelson", "warning": "You do not have access to this resource. See the Wiki for training information and resource manager contact info.", "plan": "hobbyist", "allowed": "denied", "nickname": None}
                }
                self.sendPacket(access)
            
            time = {'cmd':'time', 'time':datetime.now().strftime("%A, %d %B %Y %H:%M:%S")}
            self.sendPacket(time)
Ejemplo n.º 23
0
if __name__ == '__main__':
    app = QApplication(sys.argv)

    # self.qtappname = 'Tapioca'
    socket = QLocalSocket()
    socket.connectToServer('Tapioca')
    if socket.isOpen():
        socket.close
        socket.deleteLater()
        sys.exit(0)

    example = Example(app)

    socket.deleteLater()
    server = QLocalServer()
    server.newConnection.connect(example.restore)
    ok = server.listen('Tapioca')
    if not ok:
        if server.serverError() == QAbstractSocket.AddressInUseError:
            #print('Socket in use!')
            server.removeServer('Tapioca')
            ok = server.listen('Tapioca')
            if not ok:
                print('Socket trouble!')

    try:
        sys.exit(app.exec_())
    except:
        pass
Ejemplo n.º 24
0
class SingletonApp(QApplication):

    timeout = 1000

    def __init__(self, argv, application_id=None):
        QApplication.__init__(self, argv)

        self.socket_filename = unicode(
            os.path.expanduser("~/.ipc_%s" % self.generate_ipc_id()))
        self.shared_mem = QSharedMemory()
        self.shared_mem.setKey(self.socket_filename)

        if self.shared_mem.attach():
            self.is_running = True
            return

        self.is_running = False
        if not self.shared_mem.create(1):
            print >> sys.stderr, "Unable to create single instance"
            return
        # start local server
        self.server = QLocalServer(self)
        # connect signal for incoming connections
        self.connect(self.server, SIGNAL("newConnection()"),
                     self.receive_message)
        # if socket file exists, delete it
        if os.path.exists(self.socket_filename):
            os.remove(self.socket_filename)
        # listen
        self.server.listen(self.socket_filename)

    def __del__(self):
        self.shared_mem.detach()
        if not self.is_running:
            if os.path.exists(self.socket_filename):
                os.remove(self.socket_filename)

    def generate_ipc_id(self, channel=None):
        if channel is None:
            channel = os.path.basename(sys.argv[0])
        return "%s_%s" % (channel, getpass.getuser())

    def send_message(self, message):
        if not self.is_running:
            raise Exception(
                "Client cannot connect to IPC server. Not running.")
        socket = QLocalSocket(self)
        socket.connectToServer(self.socket_filename, QIODevice.WriteOnly)
        if not socket.waitForConnected(self.timeout):
            raise Exception(str(socket.errorString()))
        socket.write(pickle.dumps(message))
        if not socket.waitForBytesWritten(self.timeout):
            raise Exception(str(socket.errorString()))
        socket.disconnectFromServer()

    def receive_message(self):
        socket = self.server.nextPendingConnection()
        if not socket.waitForReadyRead(self.timeout):
            print >> sys.stderr, socket.errorString()
            return
        byte_array = socket.readAll()
        self.handle_new_message(pickle.loads(str(byte_array)))

    def handle_new_message(self, message):
        self.emit(SIGNAL("loadPgLayer"), message)
Ejemplo n.º 25
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("Liveplot")
        self.setWindowIcon(QIcon('icon.ico'))
        self.dockarea = DockArea()
        self.setCentralWidget(self.dockarea)
        self.namelist = NameList(self)
        self.addDockWidget(QtConst.LeftDockWidgetArea, self.namelist)
        self.server = QLocalServer()
        self.server.removeServer('LivePlot')
        self.server.listen('LivePlot')
        self.server.newConnection.connect(self.accept)
        self.bytes = bytearray()
        self.target_size = 0
        self.meta = None
        self.insert_dock_right = True
        self.conns = []
        self.shared_mems = []
        signal.signal(signal.SIGINT, self.close)

    def close(self, sig=None, frame=None):
        print 'closing'
        for conn in self.conns:
            conn.close()
        for shm in self.shared_mems:
            shm.detach()
        QApplication.instance().exit()

    def accept(self):
        logging.debug('connection accepted')
        conn = self.server.nextPendingConnection()
        conn.waitForReadyRead()
        key = str(conn.read(36))
        memory = QSharedMemory()
        memory.setKey(key)
        memory.attach()
        logging.debug('attached to memory %s with size %s' %
                      (key, memory.size()))
        atexit.register(memory.detach)
        self.conns.append(conn)
        self.shared_mems.append(memory)
        conn.readyRead.connect(lambda: self.read_from(conn, memory))
        conn.disconnected.connect(memory.detach)
        conn.write('ok')

    # noinspection PyNoneFunctionAssignment
    def read_from(self, conn, memory):
        logging.debug('reading data')
        self.meta = json.loads(conn.read(200))
        if self.meta['arrsize'] != 0:
            memory.lock()
            ba = memory.data()[0:self.meta['arrsize']]
            arr = np.frombuffer(buffer(ba))
            memory.unlock()
            conn.write('ok')
            arr = arr.reshape(self.meta['shape']).copy()
        else:
            arr = None
        self.do_operation(arr)
        if conn.bytesAvailable():
            self.read_from(conn, memory)

    #     if not self.target_size:
    #         self.meta = conn._socket.recv_json()
    #         self.target_size = self.meta['arrsize']
    #     if self.target_size > 0:
    #         n = self.target_size - len(self.bytes)
    #         data = bytearray(conn.read(n))
    #         self.bytes.extend(data)
    #     if len(self.bytes) == self.target_size:
    #         self.process_bytes()
    #     if conn.bytesAvailable():
    #         self.read_from(conn)
    #
    # def process_bytes(self):
    #     self.target_size = 0
    #     if len(self.bytes) > 0:
    #         arr = np.frombuffer(buffer(self.bytes), dtype=self.meta['dtype'])
    #         try:
    #             arr.resize(self.meta['shape'])
    #         except ValueError:
    #             arr = arr.reshape(self.meta['shape'])
    #     else:
    #         arr = None
    #     self.bytes = bytearray()
    #     self.do_operation(arr)

    def do_operation(self, arr=None):
        def clear(name):
            self.namelist[name].clear()

        def close(name):
            self.namelist[name].close()

        def remove(name):
            del self.namelist[name]

        meta = self.meta
        operation = meta['operation']
        name = meta['name']

        if name in self.namelist:
            pw = self.namelist[name]
            if pw.closed:
                pw.closed = False
                self.dockarea.addDock(pw)

        elif name == "*":
            if operation == 'clear':
                map(clear, self.namelist.keys())
            elif operation == 'close':
                map(close, self.namelist.keys())
            elif operation == 'remove':
                map(remove, self.namelist.keys())
            return
        else:
            if operation in ('clear', 'close', 'remove'):
                return
            pw = self.add_new_plot(meta['rank'], name)

        if operation == 'clear':
            pw.clear()
        elif operation == 'close':
            pw.close()
        elif operation == 'remove':
            del self.namelist[name]

        elif operation == 'plot_y':
            start_step = meta['start_step']
            label = meta['label']
            if start_step is not None:
                x0, dx = start_step
                nx = len(arr)
                xs = np.linspace(x0, x0 + (nx - 1) * dx, nx)
                pw.plot(xs, arr, name=label)
            else:
                pw.plot(arr, name=label)
        elif operation == 'plot_xy':
            label = meta['label']
            pw.plot(arr[0], arr[1], parametric=True, name=label)
        elif operation == 'plot_z':
            start_step = meta['start_step']
            if start_step is not None:
                (x0, dx), (y0, dy) = start_step
                pw.setImage(arr, pos=(x0, y0), scale=(dx, dy))
            else:
                pw.setImage(arr)
        elif operation == 'append_y':
            label = meta['label']
            xs, ys = pw.get_data(label)
            new_ys = list(ys)
            new_ys.append(meta['value'])
            start_step = meta['start_step']
            if start_step is not None:
                x0, dx = start_step
                nx = len(new_ys)
                xs = np.linspace(x0, x0 + (nx - 1) * dx, nx)
                pw.plot(xs, new_ys, name=label)
            else:
                pw.plot(new_ys, name=label)
        elif operation == 'append_xy':
            label = meta['label']
            xs, ys = pw.get_data(label)
            xn, yn = meta['value']
            new_xs = list(xs)
            new_xs.append(xn)
            new_ys = list(ys)
            new_ys.append(yn)
            pw.plot(new_xs, new_ys, parametric=True, name=label)

        elif operation == 'append_z':
            image = pw.get_data()
            if image is None:
                image = np.array([arr])
            else:
                try:
                    image = np.vstack((image, [arr]))
                except ValueError:
                    image = np.array([arr])
            start_step = meta['start_step']
            if start_step is not None:
                (x0, dx), (y0, dy) = start_step
                pw.setImage(image, pos=(x0, y0), scale=(dx, dy))
            else:
                pw.setImage(image)

        elif operation == 'label':
            pw.setTitle(meta['value'])

    def add_new_plot(self, rank, name):
        pw = widgets.get_widget(rank, name)
        self.add_plot(pw)
        self.namelist[name] = pw
        return pw

    def add_plot(self, pw):
        self.insert_dock_right = not self.insert_dock_right
        self.dockarea.addDock(pw,
                              position=['bottom',
                                        'right'][self.insert_dock_right])

    def sizeHint(self):
        return QSize(1000, 600)
Ejemplo n.º 26
0
class __IDE(QMainWindow):
    ###############################################################################
    # SIGNALS
    #
    # goingDown()
    ###############################################################################

    def __init__(self, start_server=False):
        QMainWindow.__init__(self)
        self.setWindowTitle(
            'AL\'EXA-IDE {Al\'exa-IDE Is Not Just Another IDE}')
        self.setMinimumSize(700, 500)
        #Load the size and the position of the main window
        self.load_window_geometry()
        self.__project_to_open = 0

        #Start server if needed
        self.s_listener = None
        if start_server:
            self.s_listener = QLocalServer()
            self.s_listener.listen("ninja_ide")
            self.connect(self.s_listener, SIGNAL("newConnection()"),
                         self._process_connection)

        #Profile handler
        self.profile = None
        #Opacity
        self.opacity = settings.MAX_OPACITY

        #Define Actions object before the UI
        self.actions = actions.Actions()
        #StatusBar
        self.status = status_bar.StatusBar(self)
        self.status.hide()
        self.setStatusBar(self.status)
        #Main Widget - Create first than everything else
        self.central = central_widget.CentralWidget(self)
        self.load_ui(self.central)
        self.setCentralWidget(self.central)

        #ToolBar
        self.toolbar = QToolBar(self)
        self.toolbar.setToolTip(self.tr("Press and Drag to Move"))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.addToolBar(settings.TOOLBAR_AREA, self.toolbar)
        if settings.HIDE_TOOLBAR:
            self.toolbar.hide()

        #Install Shortcuts after the UI has been initialized
        self.actions.install_shortcuts(self)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
                     self.actions.update_explorer)

        #Menu
        menubar = self.menuBar()
        file_ = menubar.addMenu(self.tr("&File"))
        edit = menubar.addMenu(self.tr("&Edit"))
        view = menubar.addMenu(self.tr("&View"))
        source = menubar.addMenu(self.tr("&Source"))
        project = menubar.addMenu(self.tr("&Project"))
        self.pluginsMenu = menubar.addMenu(self.tr("&Addins"))
        about = menubar.addMenu(self.tr("Abou&t"))

        #The order of the icons in the toolbar is defined by this calls
        self._menuFile = menu_file.MenuFile(file_, self.toolbar, self)
        self._menuView = menu_view.MenuView(view, self.toolbar, self)
        self._menuEdit = menu_edit.MenuEdit(edit, self.toolbar)
        self._menuSource = menu_source.MenuSource(source)
        self._menuProject = menu_project.MenuProject(project, self.toolbar)
        self._menuPlugins = menu_plugins.MenuPlugins(self.pluginsMenu)
        self._menuAbout = menu_about.MenuAbout(about)

        self.load_toolbar()

        #Plugin Manager
        services = {
            'editor': plugin_services.MainService(),
            'toolbar': plugin_services.ToolbarService(self.toolbar),
            'menuApp': plugin_services.MenuAppService(self.pluginsMenu),
            'explorer': plugin_services.ExplorerService(),
            'misc': plugin_services.MiscContainerService(self.misc)
        }
        serviceLocator = plugin_manager.ServiceLocator(services)
        self.plugin_manager = plugin_manager.PluginManager(
            resources.PLUGINS, serviceLocator)
        self.plugin_manager.discover()
        #load all plugins!
        self.plugin_manager.load_all()

        #Tray Icon
        self.trayIcon = updates.TrayIconUpdates(self)
        self.trayIcon.show()

        self.connect(self._menuFile, SIGNAL("openFile(QString)"),
                     self.mainContainer.open_file)
        self.connect(self.mainContainer, SIGNAL("fileSaved(QString)"),
                     self.show_status_message)
        self.connect(self.mainContainer,
                     SIGNAL("recentTabsModified(QStringList)"),
                     self._menuFile.update_recent_files)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
                     self.actions.update_migration_tips)
        self.connect(self.mainContainer, SIGNAL("updateFileMetadata(QString)"),
                     self.actions.update_migration_tips)
        self.connect(self.mainContainer, SIGNAL("migrationAnalyzed()"),
                     self.actions.update_migration_tips)

    def _process_connection(self):
        connection = self.s_listener.nextPendingConnection()
        connection.waitForReadyRead()
        data = connection.readAll()
        connection.close()
        if data:
            files, projects = str(data).split(ipc.project_delimiter, 1)
            files = [(x.split(':')[0], int(x.split(':')[1]))
                     for x in files.split(ipc.file_delimiter)]
            projects = projects.split(ipc.project_delimiter)
            self.load_session_files_projects(files, [], projects, None)

    def load_toolbar(self):
        self.toolbar.clear()
        toolbar_items = {}
        toolbar_items.update(self._menuFile.toolbar_items)
        toolbar_items.update(self._menuView.toolbar_items)
        toolbar_items.update(self._menuEdit.toolbar_items)
        toolbar_items.update(self._menuSource.toolbar_items)
        toolbar_items.update(self._menuProject.toolbar_items)

        for item in settings.TOOLBAR_ITEMS:
            if item == 'separator':
                self.toolbar.addSeparator()
            else:
                tool_item = toolbar_items.get(item, None)
                if tool_item is not None:
                    self.toolbar.addAction(tool_item)
        #load action added by plugins, This is a special case when reload
        #the toolbar after save the preferences widget
        for toolbar_action in settings.get_toolbar_item_for_plugins():
            self.toolbar.addAction(toolbar_action)

    def load_external_plugins(self, paths):
        for path in paths:
            self.plugin_manager.add_plugin_dir(path)
        #load all plugins!
        self.plugin_manager.discover()
        self.plugin_manager.load_all()

    def show_status_message(self, message):
        self.status.showMessage(message, 2000)

    def load_ui(self, centralWidget):
        #Set Application Font for ToolTips
        QToolTip.setFont(QFont(settings.FONT_FAMILY, 10))
        #Create Main Container to manage Tabs
        self.mainContainer = main_container.MainContainer(self)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
                     self.change_window_title)
        self.connect(self.mainContainer,
                     SIGNAL("locateFunction(QString, QString, bool)"),
                     self.actions.locate_function)
        self.connect(self.mainContainer, SIGNAL("navigateCode(bool, int)"),
                     self.actions.navigate_code_history)
        self.connect(self.mainContainer, SIGNAL("addBackItemNavigation()"),
                     self.actions.add_back_item_navigation)
        self.connect(self.mainContainer, SIGNAL("updateFileMetadata()"),
                     self.actions.update_explorer)
        self.connect(self.mainContainer, SIGNAL("updateLocator(QString)"),
                     self.actions.update_explorer)
        self.connect(self.mainContainer, SIGNAL("openPreferences()"),
                     self._show_preferences)
        self.connect(self.mainContainer, SIGNAL("dontOpenStartPage()"),
                     self._dont_show_start_page_again)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
                     self.status.handle_tab_changed)
        # When close the last tab cleanup
        self.connect(self.mainContainer, SIGNAL("allTabsClosed()"),
                     self._last_tab_closed)
        # Update symbols
        self.connect(self.mainContainer, SIGNAL("updateLocator(QString)"),
                     self.status.explore_file_code)
        #Create Explorer Panel
        self.explorer = explorer_container.ExplorerContainer(self)
        self.connect(self.central, SIGNAL("splitterCentralRotated()"),
                     self.explorer.rotate_tab_position)
        self.connect(self.explorer, SIGNAL("updateLocator()"),
                     self.status.explore_code)
        self.connect(self.explorer, SIGNAL("goToDefinition(int)"),
                     self.actions.editor_go_to_line)
        self.connect(self.explorer, SIGNAL("projectClosed(QString)"),
                     self.actions.close_files_from_project)
        #Create Misc Bottom Container
        self.misc = misc_container.MiscContainer(self)
        self.connect(self.mainContainer, SIGNAL("findOcurrences(QString)"),
                     self.misc.show_find_occurrences)

        centralWidget.insert_central_container(self.mainContainer)
        centralWidget.insert_lateral_container(self.explorer)
        centralWidget.insert_bottom_container(self.misc)
        if self.explorer.count() == 0:
            centralWidget.change_explorer_visibility(force_hide=True)
        self.connect(self.mainContainer,
                     SIGNAL("cursorPositionChange(int, int)"),
                     self.central.lateralPanel.update_line_col)
        # TODO: Change current symbol on move
        #self.connect(self.mainContainer,
        #SIGNAL("cursorPositionChange(int, int)"),
        #self.explorer.update_current_symbol)
        self.connect(self.mainContainer, SIGNAL("enabledFollowMode(bool)"),
                     self.central.enable_follow_mode_scrollbar)

        if settings.SHOW_START_PAGE:
            self.mainContainer.show_start_page()

    def _last_tab_closed(self):
        """
        Called when the last tasb is closed
        """
        self.explorer.cleanup_tabs()

    def _show_preferences(self):
        pref = preferences.PreferencesWidget(self.mainContainer)
        pref.show()

    def _dont_show_start_page_again(self):
        settings.SHOW_START_PAGE = False
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        qsettings.beginGroup('preferences')
        qsettings.beginGroup('general')
        qsettings.setValue('showStartPage', settings.SHOW_START_PAGE)
        qsettings.endGroup()
        qsettings.endGroup()
        self.mainContainer.actualTab.close_tab()

    def load_session_files_projects(self,
                                    filesTab1,
                                    filesTab2,
                                    projects,
                                    current_file,
                                    recent_files=None):
        self.__project_to_open = len(projects)
        self.connect(self.explorer, SIGNAL("projectOpened(QString)"),
                     self._set_editors_project_data)
        self.explorer.open_session_projects(projects, notIDEStart=False)
        self.mainContainer.open_files(filesTab1, notIDEStart=False)
        self.mainContainer.open_files(filesTab2,
                                      mainTab=False,
                                      notIDEStart=False)
        if current_file:
            self.mainContainer.open_file(current_file, notStart=False)
        if recent_files is not None:
            self._menuFile.update_recent_files(recent_files)

    def _set_editors_project_data(self):
        self.__project_to_open -= 1
        if self.__project_to_open == 0:
            self.disconnect(self.explorer, SIGNAL("projectOpened(QString)"),
                            self._set_editors_project_data)
            self.mainContainer.update_editor_project()

    def open_file(self, filename):
        if filename:
            self.mainContainer.open_file(filename)

    def open_project(self, project):
        if project:
            self.actions.open_project(project)

    def __get_profile(self):
        return self.profile

    def __set_profile(self, profileName):
        self.profile = profileName
        if self.profile is not None:
            self.setWindowTitle('AL\'EXA-IDE (PROFILE: %s)' % self.profile)
        else:
            self.setWindowTitle(
                'AL\'EXA-IDE {Al\'exa-IDE Is Not Just Another IDE}')

    Profile = property(__get_profile, __set_profile)

    def change_window_title(self, title):
        if self.profile is None:
            self.setWindowTitle('AL\'EXA-IDE - %s' % title)
        else:
            self.setWindowTitle('AL\'EXA-IDE (PROFILE: %s) - %s' %
                                (self.profile, title))
        currentEditor = self.mainContainer.get_actual_editor()
        if currentEditor is not None:
            line = currentEditor.textCursor().blockNumber() + 1
            col = currentEditor.textCursor().columnNumber()
            self.central.lateralPanel.update_line_col(line, col)

    def wheelEvent(self, event):
        if event.modifiers() == Qt.ShiftModifier:
            if event.delta() == 120 and self.opacity < settings.MAX_OPACITY:
                self.opacity += 0.1
            elif event.delta() == -120 and self.opacity > settings.MIN_OPACITY:
                self.opacity -= 0.1
            self.setWindowOpacity(self.opacity)
            event.ignore()
        else:
            QMainWindow.wheelEvent(self, event)

    def save_settings(self):
        """Save the settings before the application is closed with QSettings.

        Info saved: Tabs and projects opened, windows state(size and position).
        """
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        editor_widget = self.mainContainer.get_actual_editor()
        current_file = ''
        if editor_widget is not None:
            current_file = editor_widget.ID
        if qsettings.value('preferences/general/loadFiles', True, type=bool):
            openedFiles = self.mainContainer.get_opened_documents()
            projects_obj = self.explorer.get_opened_projects()
            projects = [p.path for p in projects_obj]
            qsettings.setValue('openFiles/projects', projects)
            if len(openedFiles) > 0:
                qsettings.setValue('openFiles/mainTab', openedFiles[0])
            if len(openedFiles) == 2:
                qsettings.setValue('openFiles/secondaryTab', openedFiles[1])
            qsettings.setValue('openFiles/currentFile', current_file)
            qsettings.setValue(
                'openFiles/recentFiles',
                self.mainContainer._tabMain.get_recent_files_list())
        qsettings.setValue('preferences/editor/bookmarks', settings.BOOKMARKS)
        qsettings.setValue('preferences/editor/breakpoints',
                           settings.BREAKPOINTS)
        qsettings.setValue('preferences/general/toolbarArea',
                           self.toolBarArea(self.toolbar))
        #Save if the windows state is maximixed
        if (self.isMaximized()):
            qsettings.setValue("window/maximized", True)
        else:
            qsettings.setValue("window/maximized", False)
            #Save the size and position of the mainwindow
            qsettings.setValue("window/size", self.size())
            qsettings.setValue("window/pos", self.pos())
        #Save the size of de splitters
        qsettings.setValue("window/central/areaSize",
                           self.central.get_area_sizes())
        qsettings.setValue("window/central/mainSize",
                           self.central.get_main_sizes())
        #Save the toolbar visibility
        if not self.toolbar.isVisible() and self.menuBar().isVisible():
            qsettings.setValue("window/hide_toolbar", True)
        else:
            qsettings.setValue("window/hide_toolbar", False)
        #Save Misc state
        qsettings.setValue("window/show_misc", self.misc.isVisible())
        #Save Profiles
        if self.profile is not None:
            self.actions.save_profile(self.profile)
        else:
            qsettings.setValue('ide/profiles', settings.PROFILES)

    def load_window_geometry(self):
        """Load from QSettings the window size of de Ninja IDE"""
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        if qsettings.value("window/maximized", True, type=bool):
            self.setWindowState(Qt.WindowMaximized)
        else:
            self.resize(
                qsettings.value("window/size",
                                QSizeF(800, 600).toSize(),
                                type='QSize'))
            self.move(
                qsettings.value("window/pos",
                                QPointF(100, 100).toPoint(),
                                type='QPoint'))

    def CloseHideAllWindow(self, close=True):
        if sys.platform == 'win32':
            import win32gui
            import win32con
            import re

            toplist, winlist = [], []

            def enum_callback(hwnd, results):
                winlist.append((hwnd, win32gui.GetWindowText(hwnd)))

            win32gui.EnumWindows(enum_callback, toplist)

            #^(?!.*details\.cfm).*selector=size.*$
            #window = [(hwnd, curTitle) for hwnd, curTitle in winlist if re.match("al.*exa.*(tool|nagios utilities|mouse and keyboard).*", curTitle, re.DOTALL | re.IGNORECASE) != None and win32gui.IsWindowVisible(hwnd) != 0]
            windows = [(hwnd, curTitle) for hwnd, curTitle in winlist]

            # just grab the hwnd for first window matching title
            #print "toplist", top
            if len(windows) > 0:
                toplist, winlist = [], []
                #print windows

                for window in windows:
                    try:
                        #if openedWindow[0].lower() == 'Al\'exa tools':
                        title = window[1]
                        if 'al\'exa tools' == title.lower(
                        ) or 'al\'exa - nagios utilities' == title.lower(
                        ) or 'al\'exa - mouse and keyboard' == title.lower(
                        ) or 'al\'exa - windows and region' == title.lower(
                        ) or 'al\'exa - process utilities' == title.lower(
                        ) or 'al\'exa - e-mail' == title.lower():
                            if close is True:
                                win32gui.PostMessage(window[0],
                                                     win32con.WM_CLOSE, 0, 0)
                            else:
                                win32gui.ShowWindow(window[0], 0)
                    except:
                        continue

    def closeEvent(self, event):

        if self.s_listener:
            self.s_listener.close()
        if (settings.CONFIRM_EXIT
                and self.mainContainer.check_for_unsaved_tabs()):
            unsaved_files = self.mainContainer.get_unsaved_files()
            txt = '\n'.join(unsaved_files)

            self.CloseHideAllWindow(False)
            val = QMessageBox.question(
                self, self.tr("Some changes were not saved"),
                (self.tr("%s\n\nDo you want to save them?") % txt),
                QMessageBox.Yes, QMessageBox.No, QMessageBox.Cancel)
            '''
            msgBox = QMessageBox()
            msgBox.setWindowTitle("QMessageBox Always On Top")
            msgBox.setText("This is an always-on-top QMessageBox!")
            msgBox.setWindowFlags(Qt.WindowStaysOnTopHint)
            msgBox.show()
            '''

            #val.setWindowFlags(Qt.WindowStaysOnTopHint)

            if val == QMessageBox.Yes:
                #Saves all open files
                self.mainContainer.save_all()
            if val == QMessageBox.Cancel:
                event.ignore()
                return
        self.emit(SIGNAL("goingDown()"))
        self.save_settings()
        completion_daemon.shutdown_daemon()
        #close python documentation server (if running)
        self.mainContainer.close_python_doc()
        #Shutdown PluginManager
        self.plugin_manager.shutdown()
        self.CloseHideAllWindow(True)

    def notify_plugin_errors(self):
        errors = self.plugin_manager.errors
        if errors:
            plugin_error_dialog = traceback_widget.PluginErrorDialog()
            for err_tuple in errors:
                plugin_error_dialog.add_traceback(err_tuple[0], err_tuple[1])
            #show the dialog
            plugin_error_dialog.exec_()

    def show_python_detection(self):
        suggested = settings.detect_python_path()
        if suggested:
            dialog = python_detect_dialog.PythonDetectDialog(suggested, self)
            dialog.show()
Ejemplo n.º 27
0
class QtSingleApplication(QApplication):

    messageReceived = pyqtSignal(unicode)

    def __init__(self, id, *argv):

        super(QtSingleApplication, self).__init__(*argv)
        self._id = id
        self._activationWindow = None
        self._activateOnMessage = False

        # Is there another instance running?
        self._outSocket = QLocalSocket()
        self._outSocket.connectToServer(self._id)
        self._isRunning = self._outSocket.waitForConnected()

        if self._isRunning:
            # Yes, there is.
            self._outStream = QTextStream(self._outSocket)
            self._outStream.setCodec('UTF-8')
        else:
            # No, there isn't.
            self._outSocket = None
            self._outStream = None
            self._inSocket = None
            self._inStream = None
            self._server = QLocalServer()
            self._server.listen(self._id)
            self._server.newConnection.connect(self._onNewConnection)

    def isRunning(self):
        return self._isRunning

    def id(self):
        return self._id

    def activationWindow(self):
        return self._activationWindow

    def setActivationWindow(self, activationWindow, activateOnMessage = True):
        self._activationWindow = activationWindow
        self._activateOnMessage = activateOnMessage

    def activateWindow(self):
        if not self._activationWindow:
            return
        self._activationWindow.setWindowState(
            self._activationWindow.windowState() & ~Qt.WindowMinimized)
        self._activationWindow.raise_()
        self._activationWindow.activateWindow()

    def sendMessage(self, msg):
        if not self._outStream:
            return False
        self._outStream << msg << '\n'
        self._outStream.flush()
        return self._outSocket.waitForBytesWritten()

    def _onNewConnection(self):
        if self._inSocket:
            self._inSocket.readyRead.disconnect(self._onReadyRead)
        self._inSocket = self._server.nextPendingConnection()
        if not self._inSocket:
            return
        self._inStream = QTextStream(self._inSocket)
        self._inStream.setCodec('UTF-8')
        self._inSocket.readyRead.connect(self._onReadyRead)
        if self._activateOnMessage:
            self.activateWindow()

    def _onReadyRead(self):
        while True:
            msg = self._inStream.readLine()
            if not msg: break
            self.messageReceived.emit(msg)
Ejemplo n.º 28
0
class IDE(QMainWindow):
    """This class is like the Sauron's Ring:
    One ring to rule them all, One ring to find them,
    One ring to bring them all and in the darkness bind them.

    This Class knows all the containers, and its know by all the containers,
    but the containers don't need to know between each other, in this way we
    can keep a better api without the need to tie the behaviour between
    the widgets, and let them just consume the 'actions' they need."""

    ###############################################################################
    # SIGNALS
    #
    # goingDown()
    ###############################################################################

    __IDESERVICES = {}
    __IDECONNECTIONS = {}
    __IDESHORTCUTS = {}
    __IDEBARCATEGORIES = {}
    __IDEMENUS = {}
    __IDETOOLBAR = {}
    # CONNECTIONS structure:
    # ({'target': service_name, 'signal_name': string, 'slot': function_obj},)
    # On modify add: {connected: True}
    __instance = None
    __created = False

    def __init__(self, start_server=False):
        QMainWindow.__init__(self)
        self.setWindowTitle('NINJA-IDE {Ninja-IDE Is Not Just Another IDE}')
        self.setMinimumSize(750, 500)
        QToolTip.setFont(QFont(settings.FONT.family(), 10))
        #Load the size and the position of the main window
        self.load_window_geometry()
        self.__project_to_open = 0

        #Editables
        self.__neditables = {}
        #Filesystem
        self.filesystem = nfilesystem.NVirtualFileSystem()

        #Sessions handler
        self._session = None
        #Opacity
        self.opacity = settings.MAX_OPACITY

        #ToolBar
        self.toolbar = QToolBar(self)
        if settings.IS_MAC_OS:
            self.toolbar.setIconSize(QSize(36, 36))
        else:
            self.toolbar.setIconSize(QSize(24, 24))
        self.toolbar.setToolTip(translations.TR_IDE_TOOLBAR_TOOLTIP)
        self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        # Set toggleViewAction text and tooltip
        self.toggleView = self.toolbar.toggleViewAction()
        self.toggleView.setText(translations.TR_TOOLBAR_VISIBILITY)
        self.toggleView.setToolTip(translations.TR_TOOLBAR_VISIBILITY)
        self.addToolBar(settings.TOOLBAR_AREA, self.toolbar)
        if settings.HIDE_TOOLBAR:
            self.toolbar.hide()
        #Notificator
        self.notification = notification.Notification(self)

        #Plugin Manager
        # CHECK ACTIVATE PLUGINS SETTING
        #services = {
        #'editor': plugin_services.MainService(),
        #'toolbar': plugin_services.ToolbarService(self.toolbar),
        ##'menuApp': plugin_services.MenuAppService(self.pluginsMenu),
        #'menuApp': plugin_services.MenuAppService(None),
        #'explorer': plugin_services.ExplorerService(),
        #'misc': plugin_services.MiscContainerService(self.misc)}
        #serviceLocator = plugin_manager.ServiceLocator(services)
        serviceLocator = plugin_manager.ServiceLocator(None)
        self.plugin_manager = plugin_manager.PluginManager(
            resources.PLUGINS, serviceLocator)
        self.plugin_manager.discover()
        #load all plugins!
        self.plugin_manager.load_all()

        #Tray Icon
        self.trayIcon = updates.TrayIconUpdates(self)
        self.connect(self.trayIcon, SIGNAL("closeTrayIcon()"),
                     self._close_tray_icon)
        self.trayIcon.show()

        key = Qt.Key_1
        for i in range(10):
            if settings.IS_MAC_OS:
                short = ui_tools.TabShortcuts(
                    QKeySequence(Qt.CTRL + Qt.ALT + key), self, i)
            else:
                short = ui_tools.TabShortcuts(QKeySequence(Qt.ALT + key), self,
                                              i)
            key += 1
            self.connect(short, SIGNAL("activated()"), self._change_tab_index)
        short = ui_tools.TabShortcuts(QKeySequence(Qt.ALT + Qt.Key_0), self,
                                      10)
        self.connect(short, SIGNAL("activated()"), self._change_tab_index)

        # Register menu categories
        IDE.register_bar_category(translations.TR_MENU_FILE, 100)
        IDE.register_bar_category(translations.TR_MENU_EDIT, 110)
        IDE.register_bar_category(translations.TR_MENU_VIEW, 120)
        IDE.register_bar_category(translations.TR_MENU_SOURCE, 130)
        IDE.register_bar_category(translations.TR_MENU_PROJECT, 140)
        IDE.register_bar_category(translations.TR_MENU_EXTENSIONS, 150)
        IDE.register_bar_category(translations.TR_MENU_ABOUT, 160)
        # Register General Menu Items
        ui_tools.install_shortcuts(self, actions.ACTIONS_GENERAL, self)

        self.register_service('ide', self)
        self.register_service('toolbar', self.toolbar)
        self.register_service('filesystem', self.filesystem)
        #Register signals connections
        connections = (
            {
                'target': 'main_container',
                'signal_name': 'fileSaved(QString)',
                'slot': self.show_message
            },
            {
                'target': 'main_container',
                'signal_name': 'currentEditorChanged(QString)',
                'slot': self.change_window_title
            },
            {
                'target': 'main_container',
                'signal_name': 'openPreferences()',
                'slot': self.show_preferences
            },
            {
                'target': 'main_container',
                'signal_name': 'allTabsClosed()',
                'slot': self._last_tab_closed
            },
            {
                'target': 'explorer_container',
                'signal_name': 'changeWindowTitle(QString)',
                'slot': self.change_window_title
            },
            {
                'target': 'explorer_container',
                'signal_name': 'projectClosed(QString)',
                'slot': self.close_project
            },
        )
        self.register_signals('ide', connections)
        # Central Widget MUST always exists
        self.central = IDE.get_service('central_container')
        self.setCentralWidget(self.central)
        # Install Services
        for service_name in self.__IDESERVICES:
            self.install_service(service_name)
        IDE.__created = True
        # Place Status Bar
        main_container = IDE.get_service('main_container')
        status_bar = IDE.get_service('status_bar')
        main_container.add_status_bar(status_bar)
        # Load Menu Bar
        menu_bar = IDE.get_service('menu_bar')
        if menu_bar:
            menu_bar.load_menu(self)
            #These two are the same service, I think that's ok
            menu_bar.load_toolbar(self)

        #Start server if needed
        self.s_listener = None
        if start_server:
            self.s_listener = QLocalServer()
            self.s_listener.listen("ninja_ide")
            self.connect(self.s_listener, SIGNAL("newConnection()"),
                         self._process_connection)

        IDE.__instance = self

    @classmethod
    def get_service(cls, service_name):
        """Return the instance of a registered service."""
        return cls.__IDESERVICES.get(service_name, None)

    def get_menuitems(self):
        """Return a dictionary with the registered menu items."""
        return IDE.__IDEMENUS

    def get_bar_categories(self):
        """Get the registered Categories for the Application menus."""
        return IDE.__IDEBARCATEGORIES

    def get_toolbaritems(self):
        """Return a dictionary with the registered menu items."""
        return IDE.__IDETOOLBAR

    @classmethod
    def register_service(cls, service_name, obj):
        """Register a service providing the service name and the instance."""
        cls.__IDESERVICES[service_name] = obj
        if cls.__created:
            cls.__instance.install_service(service_name)

    def install_service(self, service_name):
        """Activate the registered service."""
        obj = IDE.__IDESERVICES.get(service_name, None)
        func = getattr(obj, 'install', None)
        if isinstance(func, collections.Callable):
            func()
        self._connect_signals()

    def place_me_on(self, name, obj, region="central", top=False):
        """Place a widget in some of the areas in the IDE.
        @name: id to access to that widget later if needed.
        @obj: the instance of the widget to be placed.
        @region: the area where to put the widget [central, lateral]
        @top: place the widget as the first item in the split."""
        self.central.add_to_region(name, obj, region, top)

    @classmethod
    def register_signals(cls, service_name, connections):
        """Register all the signals that a particular service wants to be
        attached of.
        @service_name: id of the service
        @connections: list of dictionaries for the connection with:
            - 'target': 'the_other_service_name',
            - 'signal_name': 'name of the signal in the other service',
            - 'slot': function object in this service"""
        cls.__IDECONNECTIONS[service_name] = connections
        if cls.__created:
            cls.__instance._connect_signals()

    def _connect_signals(self):
        """Connect the signals between the different services."""
        for service_name in IDE.__IDECONNECTIONS:
            connections = IDE.__IDECONNECTIONS[service_name]
            for connection in connections:
                if connection.get('connected', False):
                    continue
                target = IDE.__IDESERVICES.get(connection['target'], None)
                slot = connection['slot']
                signal_name = connection['signal_name']
                if target and isinstance(slot, collections.Callable):
                    self.connect(target, SIGNAL(signal_name), slot)
                    connection['connected'] = True

    @classmethod
    def register_shortcut(cls, shortcut_name, shortcut, action=None):
        """Register a shortcut and action."""
        cls.__IDESHORTCUTS[shortcut_name] = (shortcut, action)

    @classmethod
    def register_menuitem(cls, menu_action, section, weight):
        """Register a QAction or QMenu in the IDE to be loaded later in the
        menubar using the section(string) to define where is going to be
        contained, and the weight define the order where is going to be
        placed.
        @menu_action: QAction or QMenu
        @section: String (name)
        @weight: int"""
        cls.__IDEMENUS[menu_action] = (section, weight)

    @classmethod
    def register_toolbar(cls, action, section, weight):
        """Register a QAction in the IDE to be loaded later in the
        toolbar using the section(string) to define where is going to be
        contained, and the weight define the order where is going to be
        placed.
        @action: QAction
        @section: String (name)
        @weight: int"""
        cls.__IDETOOLBAR[action] = (section, weight)

    @classmethod
    def register_bar_category(cls, category_name, weight):
        """Register a Menu Category to be created with the proper weight.
        @category_name: string
        @weight: int"""
        cls.__IDEBARCATEGORIES[category_name] = weight

    @classmethod
    def update_shortcut(cls, shortcut_name):
        """Update all the shortcuts of the application."""
        short = resources.get_shortcut
        shortcut, action = cls.__IDESHORTCUTS.get(shortcut_name)
        if shortcut:
            shortcut.setKey(short(shortcut_name))
        if action:
            action.setShortcut(short(shortcut_name))

    def get_or_create_nfile(self, filename):
        """For convenience access to files from ide"""
        return self.filesystem.get_file(nfile_path=filename)

    def get_or_create_editable(self, filename="", nfile=None):
        if nfile is None:
            nfile = self.filesystem.get_file(nfile_path=filename)
        editable = self.__neditables.get(nfile)
        if editable is None:
            editable = neditable.NEditable(nfile)
            self.connect(editable, SIGNAL("fileClosing(PyQt_PyObject)"),
                         self._unload_neditable)
            self.__neditables[nfile] = editable
        return editable

    def _unload_neditable(self, editable):
        self.__neditables.pop(editable.nfile)
        editable.nfile.deleteLater()
        editable.editor.deleteLater()
        editable.deleteLater()

    @property
    def opened_files(self):
        return tuple(self.__neditables.keys())

    def get_project_for_file(self, filename):
        project = None
        if filename:
            project = self.filesystem.get_project_for_file(filename)
        return project

    def create_project(self, path):
        nproj = nproject.NProject(path)
        self.filesystem.open_project(nproj)
        return nproj

    def close_project(self, project_path):
        self.filesystem.close_project(project_path)

    def get_projects(self):
        return self.filesystem.get_projects()

    def get_current_project(self):
        current_project = None
        projects = self.filesystem.get_projects()
        for project in projects:
            if projects[project].is_current:
                current_project = projects[project]
                break
        return current_project

    @classmethod
    def select_current(cls, widget):
        """Show the widget with a 4px lightblue border line."""
        widget.setProperty("highlight", True)
        widget.style().unpolish(widget)
        widget.style().polish(widget)

    @classmethod
    def unselect_current(cls, widget):
        """Remove the 4px lightblue border line from the widget."""
        widget.setProperty("highlight", False)
        widget.style().unpolish(widget)
        widget.style().polish(widget)

    def _close_tray_icon(self):
        """Close the System Tray Icon."""
        self.trayIcon.hide()
        self.trayIcon.deleteLater()

    def _change_tab_index(self):
        """Change the tabs of the current TabWidget using alt+numbers."""
        widget = QApplication.focusWidget()
        shortcut_index = getattr(widget, 'shortcut_index', None)
        if shortcut_index:
            obj = self.sender()
            shortcut_index(obj.index)

    def _process_connection(self):
        """Read the ipc input from another instance of ninja."""
        connection = self.s_listener.nextPendingConnection()
        connection.waitForReadyRead()
        data = connection.readAll()
        connection.close()
        if data:
            files, projects = str(data).split(ipc.project_delimiter, 1)
            files = [(x.split(':')[0], int(x.split(':')[1]))
                     for x in files.split(ipc.file_delimiter)]
            projects = projects.split(ipc.project_delimiter)
            self.load_session_files_projects(files, [], projects, None)

    def fullscreen_mode(self):
        """Change to fullscreen mode."""
        if self.isFullScreen():
            self.showMaximized()
        else:
            self.showFullScreen()

    def change_toolbar_visibility(self):
        """Switch the toolbar visibility"""
        if self.toolbar.isVisible():
            self.toolbar.hide()
        else:
            self.toolbar.show()

    def load_external_plugins(self, paths):
        """Load external plugins, the ones added to ninja throw the cmd."""
        for path in paths:
            self.plugin_manager.add_plugin_dir(path)
        #load all plugins!
        self.plugin_manager.discover()
        self.plugin_manager.load_all()

    def _last_tab_closed(self):
        """
        Called when the last tasb is closed
        """
        self.explorer.cleanup_tabs()

    def show_preferences(self):
        """Open the Preferences Dialog."""
        pref = preferences.Preferences(self)
        main_container = IDE.get_service("main_container")
        if main_container:
            main_container.show_dialog(pref)
        else:
            pref.show()

    def load_session_files_projects(self,
                                    files,
                                    projects,
                                    current_file,
                                    recent_files=None):
        """Load the files and projects from previous session."""
        main_container = IDE.get_service('main_container')
        projects_explorer = IDE.get_service('projects_explorer')
        if main_container and files:
            for fileData in files:
                if file_manager.file_exists(fileData[0]):
                    mtime = os.stat(fileData[0]).st_mtime
                    ignore_checkers = (mtime == fileData[2])
                    main_container.open_file(fileData[0],
                                             fileData[1],
                                             ignore_checkers=ignore_checkers)
            if current_file:
                main_container.open_file(current_file)
        if projects_explorer and projects:
            projects_explorer.load_session_projects(projects)
            #if recent_files is not None:
            #menu_file = IDE.get_service('menu_file')
            #menu_file.update_recent_files(recent_files)

    #def _set_editors_project_data(self):
    #self.__project_to_open -= 1
    #if self.__project_to_open == 0:
    #self.disconnect(self.explorer, SIGNAL("projectOpened(QString)"),
    #self._set_editors_project_data)
    #self.mainContainer.update_editor_project()

    #def open_file(self, filename):
    #if filename:
    #self.mainContainer.open_file(filename)

    #def open_project(self, project):
    #if project:
    #self.actions.open_project(project)

    def __get_session(self):
        return self._session

    def __set_session(self, sessionName):
        self._session = sessionName
        if self._session is not None:
            self.setWindowTitle(translations.TR_SESSION_IDE_HEADER %
                                {'session': self._session})
        else:
            self.setWindowTitle(
                'NINJA-IDE {Ninja-IDE Is Not Just Another IDE}')

    Session = property(__get_session, __set_session)

    def change_window_title(self, title):
        """Change the title of the Application."""
        if self._session is None:
            self.setWindowTitle('NINJA-IDE - %s' % title)
        else:
            self.setWindowTitle((translations.TR_SESSION_IDE_HEADER % {
                'session': self._session
            }) + ' - %s' % title)

    def wheelEvent(self, event):
        """Change the opacity of the application."""
        if event.modifiers() == Qt.ShiftModifier:
            if event.delta() == 120 and self.opacity < settings.MAX_OPACITY:
                self.opacity += 0.1
            elif event.delta() == -120 and self.opacity > settings.MIN_OPACITY:
                self.opacity -= 0.1
            self.setWindowOpacity(self.opacity)
            event.ignore()
        else:
            QMainWindow.wheelEvent(self, event)

    @classmethod
    def ninja_settings(cls):
        qsettings = nsettings.NSettings(resources.SETTINGS_PATH, prefix="ns")
        if cls.__created:
            cls.__instance.connect(
                qsettings, SIGNAL("valueChanged(QString, PyQt_PyObject)"),
                cls.__instance._settings_value_changed)
        return qsettings

    @classmethod
    def data_settings(cls):
        qsettings = nsettings.NSettings(resources.DATA_SETTINGS_PATH,
                                        prefix="ds")
        if cls.__created:
            cls.__instance.connect(
                qsettings, SIGNAL("valueChanged(QString, PyQt_PyObject)"),
                cls.__instance._settings_value_changed)
        return qsettings

    def _settings_value_changed(self, key, value):
        signal_name = "%s(PyQt_PyObject)" % key.replace("/", "_")
        self.emit(SIGNAL(signal_name), value)

    def save_settings(self):
        """Save the settings before the application is closed with QSettings.

        Info saved: Tabs and projects opened, windows state(size and position).
        """
        qsettings = IDE.ninja_settings()
        data_qsettings = IDE.data_settings()
        main_container = self.get_service("main_container")
        editor_widget = None
        if main_container:
            editor_widget = main_container.get_current_editor()
        current_file = ''
        if editor_widget is not None:
            current_file = editor_widget.file_path
        if qsettings.value('preferences/general/loadFiles', True, type=bool):
            openedFiles = self.filesystem.get_files()
            projects_obj = self.filesystem.get_projects()
            projects = [projects_obj[proj].path for proj in projects_obj]
            data_qsettings.setValue('lastSession/projects', projects)
            files_info = []
            for path in openedFiles:
                editable = self.__neditables.get(openedFiles[path])
                if editable is not None and editable.is_dirty:
                    stat_value = 0
                else:
                    stat_value = os.stat(path).st_mtime
                files_info.append(
                    [path,
                     editable.editor.get_cursor_position(), stat_value])
            data_qsettings.setValue('lastSession/openedFiles', files_info)
            if current_file is not None:
                data_qsettings.setValue('lastSession/currentFile',
                                        current_file)
            data_qsettings.setValue('lastSession/recentFiles',
                                    settings.LAST_OPENED_FILES)
        data_qsettings.setValue('preferences/editor/bookmarks',
                                settings.BOOKMARKS)
        data_qsettings.setValue('preferences/editor/breakpoints',
                                settings.BREAKPOINTS)

        # Session
        if self._session is not None:
            val = QMessageBox.question(
                self, translations.TR_SESSION_ACTIVE_IDE_CLOSING_TITLE,
                (translations.TR_SESSION_ACTIVE_IDE_CLOSING_BODY % {
                    'session': self.Session
                }), QMessageBox.Yes, QMessageBox.No)
            if val == QMessageBox.Yes:
                session_manager.SessionsManager.save_session_data(
                    self.Session, self)
        #qsettings.setValue('preferences/general/toolbarArea',
        #self.toolBarArea(self.toolbar))
        #Save if the windows state is maximixed
        if (self.isMaximized()):
            qsettings.setValue("window/maximized", True)
        else:
            qsettings.setValue("window/maximized", False)
            #Save the size and position of the mainwindow
            qsettings.setValue("window/size", self.size())
            qsettings.setValue("window/pos", self.pos())
        self.central.save_configuration()
        #Save the toolbar visibility
        #if not self.toolbar.isVisible() and self.menuBar().isVisible():
        #qsettings.setValue("window/hide_toolbar", True)
        #else:
        #qsettings.setValue("window/hide_toolbar", False)
        #Save Misc state
        #qsettings.setValue("window/show_region1", self.misc.isVisible())
        #Save Profiles
        #if self.profile is not None:
        #self.actions.save_profile(self.profile)
        #else:
        #qsettings.setValue('ide/profiles', settings.PROFILES)

    def activate_profile(self):
        """Show the Session Manager dialog."""
        profilesLoader = session_manager.SessionsManager(self)
        profilesLoader.show()

    def deactivate_profile(self):
        """Close the Session Session."""
        self.Session = None

    def load_window_geometry(self):
        """Load from QSettings the window size of de Ninja IDE"""
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        if qsettings.value("window/maximized", True, type=bool):
            self.setWindowState(Qt.WindowMaximized)
        else:
            self.resize(
                qsettings.value("window/size",
                                QSizeF(800, 600).toSize(),
                                type='QSize'))
            self.move(
                qsettings.value("window/pos",
                                QPointF(100, 100).toPoint(),
                                type='QPoint'))

    def _get_unsaved_files(self):
        """Return an array with the path of the unsaved files."""
        unsaved = []
        files = self.opened_files
        for f in files:
            editable = self.__neditables.get(f)
            if editable is not None and editable.editor.is_modified:
                unsaved.append(f)
        return unsaved

    def _save_unsaved_files(self, files):
        """Save the files from the paths in the array."""
        for f in files:
            editable = self.get_or_create_editable(f)
            editable.ignore_checkers = True
            editable.save_content()

    def closeEvent(self, event):
        """Saves some global settings before closing."""
        if self.s_listener:
            self.s_listener.close()
        main_container = self.get_service("main_container")
        unsaved_files = self._get_unsaved_files()
        if (settings.CONFIRM_EXIT and unsaved_files):
            txt = '\n'.join([nfile.file_name for nfile in unsaved_files])
            val = QMessageBox.question(
                self, translations.TR_IDE_CONFIRM_EXIT_TITLE,
                (translations.TR_IDE_CONFIRM_EXIT_BODY % {
                    'files': txt
                }), QMessageBox.Yes, QMessageBox.No, QMessageBox.Cancel)
            if val == QMessageBox.Yes:
                #Saves all open files
                self._save_unsaved_files(unsaved_files)
            if val == QMessageBox.Cancel:
                event.ignore()
                return
        self.save_settings()
        self.emit(SIGNAL("goingDown()"))
        #close python documentation server (if running)
        main_container.close_python_doc()
        #Shutdown PluginManager
        self.plugin_manager.shutdown()
        #completion_daemon.shutdown_daemon()
        super(IDE, self).closeEvent(event)

    def notify_plugin_errors(self):
        #TODO: Check if the Plugin Error dialog can be improved
        errors = self.plugin_manager.errors
        if errors:
            plugin_error_dialog = traceback_widget.PluginErrorDialog()
            for err_tuple in errors:
                plugin_error_dialog.add_traceback(err_tuple[0], err_tuple[1])
            #show the dialog
            plugin_error_dialog.exec_()

    def show_message(self, message, duration=3000):
        """Show status message."""
        self.notification.set_message(message, duration)
        self.notification.show()

    def show_plugins_store(self):
        """Open the Plugins Manager to install/uninstall plugins."""
        store = plugins_store.PluginsStore(self)
        main_container = IDE.get_service("main_container")
        if main_container:
            main_container.show_dialog(store)
        else:
            store.show()

    def show_languages(self):
        """Open the Language Manager to install/uninstall languages."""
        manager = language_manager.LanguagesManagerWidget(self)
        manager.show()

    def show_schemes(self):
        """Open the Schemes Manager to install/uninstall schemes."""
        manager = schemes_manager.SchemesManagerWidget(self)
        manager.show()

    def show_about_qt(self):
        """Show About Qt Dialog."""
        QMessageBox.aboutQt(self, translations.TR_ABOUT_QT)

    def show_about_ninja(self):
        """Show About NINJA-IDE Dialog."""
        about = about_ninja.AboutNinja(self)
        about.show()

    def show_python_detection(self):
        """Show Python detection dialog for windows."""
        #TODO: Notify the user when no python version could be found
        suggested = settings.detect_python_path()
        if suggested:
            dialog = python_detect_dialog.PythonDetectDialog(suggested, self)
            dialog.show()
Ejemplo n.º 29
0
class IDE(QMainWindow):
    """This class is like the Sauron's Ring:
    One ring to rule them all, One ring to find them,
    One ring to bring them all and in the darkness bind them.

    This Class knows all the containers, and its know by all the containers,
    but the containers don't need to know between each other, in this way we
    can keep a better api without the need to tie the behaviour between
    the widgets, and let them just consume the 'actions' they need."""

###############################################################################
# SIGNALS
#
# goingDown()
###############################################################################

    __IDESERVICES = {}
    __IDECONNECTIONS = {}
    __IDESHORTCUTS = {}
    __IDEBARCATEGORIES = {}
    __IDEMENUS = {}
    __IDETOOLBAR = {}
    # CONNECTIONS structure:
    # ({'target': service_name, 'signal_name': string, 'slot': function_obj},)
    # On modify add: {connected: True}
    __instance = None
    __created = False

    def __init__(self, start_server=False):
        QMainWindow.__init__(self)
        self.setWindowTitle('NINJA-IDE {Ninja-IDE Is Not Just Another IDE}')
        self.setMinimumSize(750, 500)
        QToolTip.setFont(QFont(settings.FONT.family(), 10))
        #Load the size and the position of the main window
        self.load_window_geometry()
        self.__project_to_open = 0

        #Editables
        self.__neditables = {}
        #Filesystem
        self.filesystem = nfilesystem.NVirtualFileSystem()

        #Start server if needed
        self.s_listener = None
        if start_server:
            self.s_listener = QLocalServer()
            self.s_listener.listen("ninja_ide")
            self.connect(self.s_listener, SIGNAL("newConnection()"),
                         self._process_connection)

        #Sessions handler
        self._session = None
        #Opacity
        self.opacity = settings.MAX_OPACITY

        #ToolBar
        self.toolbar = QToolBar(self)
        if settings.IS_MAC_OS:
            self.toolbar.setIconSize(QSize(36, 36))
        else:
            self.toolbar.setIconSize(QSize(24, 24))
        self.toolbar.setToolTip(translations.TR_IDE_TOOLBAR_TOOLTIP)
        self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        # Set toggleViewAction text and tooltip
        self.toggleView = self.toolbar.toggleViewAction()
        self.toggleView.setText(translations.TR_TOOLBAR_VISIBILITY)
        self.toggleView.setToolTip(translations.TR_TOOLBAR_VISIBILITY)
        self.addToolBar(settings.TOOLBAR_AREA, self.toolbar)
        if settings.HIDE_TOOLBAR:
            self.toolbar.hide()
        #Notificator
        self.notification = notification.Notification(self)

        #Plugin Manager
        # CHECK ACTIVATE PLUGINS SETTING
        #services = {
            #'editor': plugin_services.MainService(),
            #'toolbar': plugin_services.ToolbarService(self.toolbar),
            ##'menuApp': plugin_services.MenuAppService(self.pluginsMenu),
            #'menuApp': plugin_services.MenuAppService(None),
            #'explorer': plugin_services.ExplorerService(),
            #'misc': plugin_services.MiscContainerService(self.misc)}
        #serviceLocator = plugin_manager.ServiceLocator(services)
        serviceLocator = plugin_manager.ServiceLocator(None)
        self.plugin_manager = plugin_manager.PluginManager(resources.PLUGINS,
                                                           serviceLocator)
        self.plugin_manager.discover()
        #load all plugins!
        self.plugin_manager.load_all()

        #Tray Icon
        self.trayIcon = updates.TrayIconUpdates(self)
        self.connect(self.trayIcon, SIGNAL("closeTrayIcon()"),
                     self._close_tray_icon)
        self.trayIcon.show()

        key = Qt.Key_1
        for i in range(10):
            if settings.IS_MAC_OS:
                short = ui_tools.TabShortcuts(
                    QKeySequence(Qt.CTRL + Qt.ALT + key), self, i)
            else:
                short = ui_tools.TabShortcuts(
                    QKeySequence(Qt.ALT + key), self, i)
            key += 1
            self.connect(short, SIGNAL("activated()"), self._change_tab_index)
        short = ui_tools.TabShortcuts(QKeySequence(Qt.ALT + Qt.Key_0), self, 10)
        self.connect(short, SIGNAL("activated()"), self._change_tab_index)

        # Register menu categories
        IDE.register_bar_category(translations.TR_MENU_FILE, 100)
        IDE.register_bar_category(translations.TR_MENU_EDIT, 110)
        IDE.register_bar_category(translations.TR_MENU_VIEW, 120)
        IDE.register_bar_category(translations.TR_MENU_SOURCE, 130)
        IDE.register_bar_category(translations.TR_MENU_PROJECT, 140)
        IDE.register_bar_category(translations.TR_MENU_EXTENSIONS, 150)
        IDE.register_bar_category(translations.TR_MENU_ABOUT, 160)
        # Register General Menu Items
        ui_tools.install_shortcuts(self, actions.ACTIONS_GENERAL, self)

        self.register_service('ide', self)
        self.register_service('toolbar', self.toolbar)
        #Register signals connections
        connections = (
            {'target': 'main_container',
             'signal_name': 'fileSaved(QString)',
             'slot': self.show_message},
            {'target': 'main_container',
             'signal_name': 'currentEditorChanged(QString)',
             'slot': self.change_window_title},
            {'target': 'main_container',
             'signal_name': 'openPreferences()',
             'slot': self.show_preferences},
            {'target': 'main_container',
             'signal_name': 'allTabsClosed()',
             'slot': self._last_tab_closed},
            {'target': 'explorer_container',
             'signal_name': 'changeWindowTitle(QString)',
             'slot': self.change_window_title},
            {'target': 'explorer_container',
             'signal_name': 'projectClosed(QString)',
             'slot': self.close_project},
            )
        self.register_signals('ide', connections)
        # Central Widget MUST always exists
        self.central = IDE.get_service('central_container')
        self.setCentralWidget(self.central)
        # Install Services
        for service_name in self.__IDESERVICES:
            self.install_service(service_name)
        IDE.__created = True
        menu_bar = IDE.get_service('menu_bar')
        if menu_bar:
            menu_bar.load_menu(self)
            #These two are the same service, I think that's ok
            menu_bar.load_toolbar(self)
        IDE.__instance = self

    @classmethod
    def get_service(cls, service_name):
        """Return the instance of a registered service."""
        return cls.__IDESERVICES.get(service_name, None)

    def get_menuitems(self):
        """Return a dictionary with the registered menu items."""
        return IDE.__IDEMENUS

    def get_bar_categories(self):
        """Get the registered Categories for the Application menus."""
        return IDE.__IDEBARCATEGORIES

    def get_toolbaritems(self):
        """Return a dictionary with the registered menu items."""
        return IDE.__IDETOOLBAR

    @classmethod
    def register_service(cls, service_name, obj):
        """Register a service providing the service name and the instance."""
        cls.__IDESERVICES[service_name] = obj
        if cls.__created:
            cls.__instance.install_service(service_name)

    def install_service(self, service_name):
        """Activate the registered service."""
        obj = IDE.__IDESERVICES.get(service_name, None)
        func = getattr(obj, 'install', None)
        if isinstance(func, collections.Callable):
            func()
        self._connect_signals()

    def place_me_on(self, name, obj, region="central", top=False):
        """Place a widget in some of the areas in the IDE.
        @name: id to access to that widget later if needed.
        @obj: the instance of the widget to be placed.
        @region: the area where to put the widget [central, lateral]
        @top: place the widget as the first item in the split."""
        self.central.add_to_region(name, obj, region, top)

    @classmethod
    def register_signals(cls, service_name, connections):
        """Register all the signals that a particular service wants to be
        attached of.
        @service_name: id of the service
        @connections: list of dictionaries for the connection with:
            - 'target': 'the_other_service_name',
            - 'signal_name': 'name of the signal in the other service',
            - 'slot': function object in this service"""
        cls.__IDECONNECTIONS[service_name] = connections
        if cls.__created:
            cls.__instance._connect_signals()

    def _connect_signals(self):
        """Connect the signals between the different services."""
        for service_name in IDE.__IDECONNECTIONS:
            connections = IDE.__IDECONNECTIONS[service_name]
            for connection in connections:
                if connection.get('connected', False):
                    continue
                target = IDE.__IDESERVICES.get(
                    connection['target'], None)
                slot = connection['slot']
                signal_name = connection['signal_name']
                if target and isinstance(slot, collections.Callable):
                    self.connect(target, SIGNAL(signal_name), slot)
                    connection['connected'] = True

    @classmethod
    def register_shortcut(cls, shortcut_name, shortcut, action=None):
        """Register a shortcut and action."""
        cls.__IDESHORTCUTS[shortcut_name] = (shortcut, action)

    @classmethod
    def register_menuitem(cls, menu_action, section, weight):
        """Register a QAction or QMenu in the IDE to be loaded later in the
        menubar using the section(string) to define where is going to be
        contained, and the weight define the order where is going to be
        placed.
        @menu_action: QAction or QMenu
        @section: String (name)
        @weight: int"""
        cls.__IDEMENUS[menu_action] = (section, weight)

    @classmethod
    def register_toolbar(cls, action, section, weight):
        """Register a QAction in the IDE to be loaded later in the
        toolbar using the section(string) to define where is going to be
        contained, and the weight define the order where is going to be
        placed.
        @action: QAction
        @section: String (name)
        @weight: int"""
        cls.__IDETOOLBAR[action] = (section, weight)

    @classmethod
    def register_bar_category(cls, category_name, weight):
        """Register a Menu Category to be created with the proper weight.
        @category_name: string
        @weight: int"""
        cls.__IDEBARCATEGORIES[category_name] = weight

    @classmethod
    def update_shortcut(cls, shortcut_name):
        """Update all the shortcuts of the application."""
        short = resources.get_shortcut
        shortcut, action = cls.__IDESHORTCUTS.get(shortcut_name)
        if shortcut:
            shortcut.setKey(short(shortcut_name))
        if action:
            action.setShortcut(short(shortcut_name))

    def get_or_create_nfile(self, filename):
        """For convenience access to files from ide"""
        return self.filesystem.get_file(nfile_path=filename)

    def get_or_create_editable(self, filename="", nfile=None):
        if nfile is None:
            nfile = self.filesystem.get_file(nfile_path=filename)
        editable = self.__neditables.get(nfile)
        if editable is None:
            editable = neditable.NEditable(nfile)
            self.connect(editable, SIGNAL("fileClosing(PyQt_PyObject)"),
                         self._unload_neditable)
            self.__neditables[nfile] = editable
        return editable

    def _unload_neditable(self, editable):
        self.__neditables.pop(editable.nfile)
        editable.nfile.deleteLater()
        editable.editor.deleteLater()
        editable.deleteLater()

    @property
    def opened_files(self):
        return tuple(self.__neditables.keys())

    def get_project_for_file(self, filename):
        project = None
        if filename:
            project = self.filesystem.get_project_for_file(filename)
        return project

    def create_project(self, path):
        nproj = nproject.NProject(path)
        self.filesystem.open_project(nproj)
        return nproj

    def close_project(self, project_path):
        self.filesystem.close_project(project_path)

    def get_projects(self):
        return self.filesystem.get_projects()

    def get_current_project(self):
        current_project = None
        projects = self.filesystem.get_projects()
        for project in projects:
            if projects[project].is_current:
                current_project = projects[project]
                break
        return current_project

    @classmethod
    def select_current(cls, widget):
        """Show the widget with a 4px lightblue border line."""
        widget.setProperty("highlight", True)
        widget.style().unpolish(widget)
        widget.style().polish(widget)

    @classmethod
    def unselect_current(cls, widget):
        """Remove the 4px lightblue border line from the widget."""
        widget.setProperty("highlight", False)
        widget.style().unpolish(widget)
        widget.style().polish(widget)

    def _close_tray_icon(self):
        """Close the System Tray Icon."""
        self.trayIcon.hide()
        self.trayIcon.deleteLater()

    def _change_tab_index(self):
        """Change the tabs of the current TabWidget using alt+numbers."""
        widget = QApplication.focusWidget()
        shortcut_index = getattr(widget, 'shortcut_index', None)
        if shortcut_index:
            obj = self.sender()
            shortcut_index(obj.index)

    def _process_connection(self):
        """Read the ipc input from another instance of ninja."""
        connection = self.s_listener.nextPendingConnection()
        connection.waitForReadyRead()
        data = connection.readAll()
        connection.close()
        if data:
            files, projects = str(data).split(ipc.project_delimiter, 1)
            files = [(x.split(':')[0], int(x.split(':')[1]))
                     for x in files.split(ipc.file_delimiter)]
            projects = projects.split(ipc.project_delimiter)
            self.load_session_files_projects(files, [], projects, None)

    def fullscreen_mode(self):
        """Change to fullscreen mode."""
        if self.isFullScreen():
            self.showMaximized()
        else:
            self.showFullScreen()

    def change_toolbar_visibility(self):
        """Switch the toolbar visibility"""
        if self.toolbar.isVisible():
            self.toolbar.hide()
        else:
            self.toolbar.show()

    def load_external_plugins(self, paths):
        """Load external plugins, the ones added to ninja throw the cmd."""
        for path in paths:
            self.plugin_manager.add_plugin_dir(path)
        #load all plugins!
        self.plugin_manager.discover()
        self.plugin_manager.load_all()

    def _last_tab_closed(self):
        """
        Called when the last tasb is closed
        """
        self.explorer.cleanup_tabs()

    def show_preferences(self):
        """Open the Preferences Dialog."""
        pref = preferences.Preferences(self)
        pref.show()

    def load_session_files_projects(self, files, projects,
                                    current_file, recent_files=None):
        """Load the files and projects from previous session."""
        main_container = IDE.get_service('main_container')
        projects_explorer = IDE.get_service('projects_explorer')
        if main_container and files:
            for fileData in files:
                if file_manager.file_exists(fileData[0]):
                    mtime = os.stat(fileData[0]).st_mtime
                    ignore_checkers = (mtime == fileData[2])
                    main_container.open_file(fileData[0], fileData[1],
                                             ignore_checkers=ignore_checkers)
            if current_file:
                main_container.open_file(current_file)
        if projects_explorer and projects:
            projects_explorer.load_session_projects(projects)
            #if recent_files is not None:
                #menu_file = IDE.get_service('menu_file')
                #menu_file.update_recent_files(recent_files)

    #def _set_editors_project_data(self):
        #self.__project_to_open -= 1
        #if self.__project_to_open == 0:
            #self.disconnect(self.explorer, SIGNAL("projectOpened(QString)"),
                #self._set_editors_project_data)
            #self.mainContainer.update_editor_project()

    #def open_file(self, filename):
        #if filename:
            #self.mainContainer.open_file(filename)

    #def open_project(self, project):
        #if project:
            #self.actions.open_project(project)

    def __get_session(self):
        return self._session

    def __set_session(self, sessionName):
        self._session = sessionName
        if self._session is not None:
            self.setWindowTitle(translations.TR_SESSION_IDE_HEADER %
                                {'session': self._session})
        else:
            self.setWindowTitle(
                'NINJA-IDE {Ninja-IDE Is Not Just Another IDE}')

    Session = property(__get_session, __set_session)

    def change_window_title(self, title):
        """Change the title of the Application."""
        if self._session is None:
            self.setWindowTitle('NINJA-IDE - %s' % title)
        else:
            self.setWindowTitle((translations.TR_SESSION_IDE_HEADER %
                                {'session': self._session}) + ' - %s' % title)

    def wheelEvent(self, event):
        """Change the opacity of the application."""
        if event.modifiers() == Qt.ShiftModifier:
            if event.delta() == 120 and self.opacity < settings.MAX_OPACITY:
                self.opacity += 0.1
            elif event.delta() == -120 and self.opacity > settings.MIN_OPACITY:
                self.opacity -= 0.1
            self.setWindowOpacity(self.opacity)
            event.ignore()
        else:
            QMainWindow.wheelEvent(self, event)

    @classmethod
    def ninja_settings(cls):
        qsettings = nsettings.NSettings(resources.SETTINGS_PATH,
                                        prefix="ns")
        if cls.__created:
            cls.__instance.connect(
                qsettings,
                SIGNAL("valueChanged(QString, PyQt_PyObject)"),
                cls.__instance._settings_value_changed)
        return qsettings

    @classmethod
    def data_settings(cls):
        qsettings = nsettings.NSettings(resources.DATA_SETTINGS_PATH,
                                        prefix="ds")
        if cls.__created:
            cls.__instance.connect(
                qsettings,
                SIGNAL("valueChanged(QString, PyQt_PyObject)"),
                cls.__instance._settings_value_changed)
        return qsettings

    def _settings_value_changed(self, key, value):
        signal_name = "%s(PyQt_PyObject)" % key.replace("/", "_")
        self.emit(SIGNAL(signal_name), value)

    def save_settings(self):
        """Save the settings before the application is closed with QSettings.

        Info saved: Tabs and projects opened, windows state(size and position).
        """
        qsettings = IDE.ninja_settings()
        data_qsettings = IDE.data_settings()
        main_container = self.get_service("main_container")
        editor_widget = None
        if main_container:
            editor_widget = main_container.get_current_editor()
        current_file = ''
        if editor_widget is not None:
            current_file = editor_widget.file_path
        if qsettings.value('preferences/general/loadFiles', True, type=bool):
            openedFiles = self.filesystem.get_files()
            projects_obj = self.filesystem.get_projects()
            projects = [projects_obj[proj].path for proj in projects_obj]
            data_qsettings.setValue('lastSession/projects', projects)
            files_info = []
            for path in openedFiles:
                editable = self.__neditables.get(openedFiles[path])
                if editable is not None and editable.is_dirty:
                    stat_value = 0
                else:
                    stat_value = os.stat(path).st_mtime
                files_info.append([path,
                                  editable.editor.get_cursor_position(),
                                  stat_value])
            data_qsettings.setValue('lastSession/openedFiles', files_info)
            if current_file is not None:
                data_qsettings.setValue('lastSession/currentFile', current_file)
            data_qsettings.setValue('lastSession/recentFiles',
                                    settings.LAST_OPENED_FILES)
        data_qsettings.setValue('preferences/editor/bookmarks',
                                settings.BOOKMARKS)
        data_qsettings.setValue('preferences/editor/breakpoints',
                                settings.BREAKPOINTS)

        # Session
        if self._session is not None:
            val = QMessageBox.question(
                self,
                translations.TR_SESSION_ACTIVE_IDE_CLOSING_TITLE,
                (translations.TR_SESSION_ACTIVE_IDE_CLOSING_BODY %
                    {'session': self.Session}),
                QMessageBox.Yes, QMessageBox.No)
            if val == QMessageBox.Yes:
                session_manager.SessionsManager.save_session_data(
                    self.Session, self)
        #qsettings.setValue('preferences/general/toolbarArea',
            #self.toolBarArea(self.toolbar))
        #Save if the windows state is maximixed
        if(self.isMaximized()):
            qsettings.setValue("window/maximized", True)
        else:
            qsettings.setValue("window/maximized", False)
            #Save the size and position of the mainwindow
            qsettings.setValue("window/size", self.size())
            qsettings.setValue("window/pos", self.pos())
        self.central.save_configuration()
        #Save the toolbar visibility
        #if not self.toolbar.isVisible() and self.menuBar().isVisible():
            #qsettings.setValue("window/hide_toolbar", True)
        #else:
            #qsettings.setValue("window/hide_toolbar", False)
        #Save Misc state
        #qsettings.setValue("window/show_region1", self.misc.isVisible())
        #Save Profiles
        #if self.profile is not None:
            #self.actions.save_profile(self.profile)
        #else:
            #qsettings.setValue('ide/profiles', settings.PROFILES)

    def activate_profile(self):
        """Show the Session Manager dialog."""
        profilesLoader = session_manager.SessionsManager(self)
        profilesLoader.show()

    def deactivate_profile(self):
        """Close the Session Session."""
        self.Session = None

    def load_window_geometry(self):
        """Load from QSettings the window size of de Ninja IDE"""
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        if qsettings.value("window/maximized", True, type=bool):
            self.setWindowState(Qt.WindowMaximized)
        else:
            self.resize(qsettings.value(
                "window/size",
                QSizeF(800, 600).toSize(), type='QSize'))
            self.move(qsettings.value(
                "window/pos",
                QPointF(100, 100).toPoint(), type='QPoint'))

    def _get_unsaved_files(self):
        """Return an array with the path of the unsaved files."""
        unsaved = []
        files = self.filesystem.get_files()
        for f in files:
            editable = self.__neditables.get(files[f])
            if editable is not None:
                if editable.editor.is_modified:
                    unsaved.append(f)
        return unsaved

    def _save_unsaved_files(self, files):
        """Save the files from the paths in the array."""
        for f in files:
            editable = self.get_or_create_editable(f)
            editable.ignore_checkers = True
            editable.save_content()

    def closeEvent(self, event):
        """Saves some global settings before closing."""
        if self.s_listener:
            self.s_listener.close()
        main_container = self.get_service("main_container")
        unsaved_files = self._get_unsaved_files()
        if (settings.CONFIRM_EXIT and unsaved_files):
            txt = '\n'.join(unsaved_files)
            val = QMessageBox.question(
                self,
                translations.TR_IDE_CONFIRM_EXIT_TITLE,
                (translations.TR_IDE_CONFIRM_EXIT_BODY % {'files': txt}),
                QMessageBox.Yes, QMessageBox.No, QMessageBox.Cancel)
            if val == QMessageBox.Yes:
                #Saves all open files
                self._save_unsaved_files(unsaved_files)
            if val == QMessageBox.Cancel:
                event.ignore()
                return
        self.save_settings()
        self.emit(SIGNAL("goingDown()"))
        #close python documentation server (if running)
        main_container.close_python_doc()
        #Shutdown PluginManager
        self.plugin_manager.shutdown()
        #completion_daemon.shutdown_daemon()
        super(IDE, self).closeEvent(event)

    def notify_plugin_errors(self):
        #TODO: Check if the Plugin Error dialog can be improved
        errors = self.plugin_manager.errors
        if errors:
            plugin_error_dialog = traceback_widget.PluginErrorDialog()
            for err_tuple in errors:
                plugin_error_dialog.add_traceback(err_tuple[0], err_tuple[1])
            #show the dialog
            plugin_error_dialog.exec_()

    def show_message(self, message, duration=3000):
        """Show status message."""
        self.notification.set_message(message, duration)
        self.notification.show()

    def show_plugins_store(self):
        """Open the Plugins Manager to install/uninstall plugins."""
        store = plugins_store.PluginsStore(self)
        store.show()
        #manager = plugins_manager.PluginsManagerWidget(self)
        #manager.show()
        #if manager._requirements:
            #dependencyDialog = plugins_manager.DependenciesHelpDialog(
                #manager._requirements)
            #dependencyDialog.show()

    def show_languages(self):
        """Open the Language Manager to install/uninstall languages."""
        manager = language_manager.LanguagesManagerWidget(self)
        manager.show()

    def show_schemes(self):
        """Open the Schemes Manager to install/uninstall schemes."""
        manager = schemes_manager.SchemesManagerWidget(self)
        manager.show()

    def show_about_qt(self):
        """Show About Qt Dialog."""
        QMessageBox.aboutQt(self, translations.TR_ABOUT_QT)

    def show_about_ninja(self):
        """Show About NINJA-IDE Dialog."""
        about = about_ninja.AboutNinja(self)
        about.show()

    def show_python_detection(self):
        """Show Python detection dialog for windows."""
        #TODO: Notify the user when no python version could be found
        suggested = settings.detect_python_path()
        if suggested:
            dialog = python_detect_dialog.PythonDetectDialog(suggested, self)
            dialog.show()
Ejemplo n.º 30
0
class SingletonApp(QApplication):
    '''
    Simple server based on QLocalServer, QLocalSocket, QSharedMemory
    that sends and receives messages and data with a socket connection and shared memory
    '''
    timeout = 1000
    running_apps = []
    def __init__(self, argv=sys.argv, application_id=None, size=2**24):
        QApplication.__init__(self, argv)
        self.socket_filename = os.path.expanduser(os.path.join(os.getcwd(),'.ipc_%s' % self.generate_ipc_id()))
        self.shared_mem = QSharedMemory()
        self.shared_mem.setKey(self.socket_filename)

        if self.shared_mem.attach():
            self.is_running = True
            return

        self.is_running = False
        if not self.shared_mem.create(size):
            print >>sys.stderr, "Unable to create single instance"
            return
        # start local server
        self.server = QLocalServer(self)
        # connect signal for incoming connections
        self.connect(self.server, SIGNAL("newConnection()"), self.receive_message)
        # if socket file exists, delete it
        if os.path.exists(self.socket_filename):
            os.remove(self.socket_filename)
        # listen
        self.server.listen(self.socket_filename)
        SingletonApp.running_apps.append(self)

    def __del__(self):
        logging.debug('Detaching shared memory and closing socket connection.')
        self.shared_mem.detach()
        if not self.is_running:
            if os.path.exists(self.socket_filename):
                os.remove(self.socket_filename)

    def generate_ipc_id(self, channel=None):
        if channel:
            return '%s_%s' %(channel,getpass.get_user())
        else:
            return getpass.getuser()

    def send_message(self, message):
        if not self.is_running:
            raise Exception("Client cannot connect to IPC server. Not running.")
        socket = QLocalSocket(self)
        socket.connectToServer(self.socket_filename, QIODevice.WriteOnly)
        if not socket.waitForConnected(self.timeout):
            self.__del__()
            if not socket.waitForConnected(self.timeout):
                raise Exception(str(socket.errorString()))
        socket.write(pickle.dumps(message))
        if not socket.waitForBytesWritten(self.timeout):
            raise Exception(str(socket.errorString()))
        socket.disconnectFromServer()

    def receive_message(self):
        socket = self.server.nextPendingConnection()
        if not socket.waitForReadyRead(self.timeout):
            print >>sys.stderr, socket.errorString()
            return
        byte_array = socket.readAll()
        self.handle_new_message(pickle.loads(byte_array))

    def handle_new_message(self, message):
        logging.debug("Received: %s" %message)
Ejemplo n.º 31
0
class __IDE(QMainWindow):
    ###############################################################################
    # SIGNALS
    #
    # goingDown()
    ###############################################################################

    def __init__(self, start_server=False):
        QMainWindow.__init__(self)
        self.setWindowTitle('NINJA-IDE {Ninja-IDE Is Not Just Another IDE}')
        self.setMinimumSize(700, 500)
        #Load the size and the position of the main window
        self.load_window_geometry()

        #Start server if needed
        self.s_listener = None
        if start_server:
            self.s_listener = QLocalServer()
            self.s_listener.listen("ninja_ide")
            self.connect(self.s_listener, SIGNAL("newConnection()"),
                         self._process_connection)

        #Profile handler
        self.profile = None
        #Opacity
        self.opacity = settings.MAX_OPACITY

        #Define Actions object before the UI
        self.actions = actions.Actions()
        #StatusBar
        self.status = status_bar.StatusBar(self)
        self.status.hide()
        self.setStatusBar(self.status)
        #Main Widget - Create first than everything else
        self.central = central_widget.CentralWidget(self)
        self.load_ui(self.central)
        self.setCentralWidget(self.central)

        #ToolBar
        self.toolbar = QToolBar(self)
        self.toolbar.setToolTip(self.tr("Press and Drag to Move"))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.addToolBar(settings.TOOLBAR_AREA, self.toolbar)
        if settings.HIDE_TOOLBAR:
            self.toolbar.hide()

        #Install Shortcuts after the UI has been initialized
        self.actions.install_shortcuts(self)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
                     self.actions.update_explorer)

        #Menu
        menubar = self.menuBar()
        file_ = menubar.addMenu(self.tr("&File"))
        edit = menubar.addMenu(self.tr("&Edit"))
        view = menubar.addMenu(self.tr("&View"))
        source = menubar.addMenu(self.tr("&Source"))
        project = menubar.addMenu(self.tr("&Project"))
        self.pluginsMenu = menubar.addMenu(self.tr("&Addins"))
        about = menubar.addMenu(self.tr("Abou&t"))

        #The order of the icons in the toolbar is defined by this calls
        self._menuFile = menu_file.MenuFile(file_, self.toolbar, self)
        self._menuView = menu_view.MenuView(view, self.toolbar, self)
        self._menuEdit = menu_edit.MenuEdit(edit, self.toolbar)
        self._menuSource = menu_source.MenuSource(source)
        self._menuProject = menu_project.MenuProject(project, self.toolbar)
        self._menuPlugins = menu_plugins.MenuPlugins(self.pluginsMenu)
        self._menuAbout = menu_about.MenuAbout(about)

        self.load_toolbar()

        #Plugin Manager
        services = {
            'editor': plugin_services.MainService(),
            'toolbar': plugin_services.ToolbarService(self.toolbar),
            'menuApp': plugin_services.MenuAppService(self.pluginsMenu),
            'explorer': plugin_services.ExplorerService(),
            'misc': plugin_services.MiscContainerService(self.misc)
        }
        serviceLocator = plugin_manager.ServiceLocator(services)
        self.plugin_manager = plugin_manager.PluginManager(
            resources.PLUGINS, serviceLocator)
        self.plugin_manager.discover()
        #load all plugins!
        self.plugin_manager.load_all()

        #Tray Icon
        self.trayIcon = updates.TrayIconUpdates(self)
        self.trayIcon.show()

        self.connect(self._menuFile, SIGNAL("openFile(QString)"),
                     self.mainContainer.open_file)
        self.connect(self.mainContainer, SIGNAL("fileSaved(QString)"),
                     self.show_status_message)
        self.connect(self.mainContainer,
                     SIGNAL("recentTabsModified(QStringList)"),
                     self._menuFile.update_recent_files)

    def _process_connection(self):
        connection = self.s_listener.nextPendingConnection()
        connection.waitForReadyRead()
        data = connection.readAll()
        connection.close()
        if data:
            files, projects = data.split(ipc.project_delimiter, 1)
            files = map(lambda x: (x.split(':')[0], int(x.split(':')[1])),
                        files.split(ipc.file_delimiter))
            projects = projects.split(ipc.project_delimiter)
            self.load_session_files_projects(files, [], projects, None)

    def load_toolbar(self):
        self.toolbar.clear()
        toolbar_items = {}
        toolbar_items.update(self._menuFile.toolbar_items)
        toolbar_items.update(self._menuView.toolbar_items)
        toolbar_items.update(self._menuEdit.toolbar_items)
        toolbar_items.update(self._menuSource.toolbar_items)
        toolbar_items.update(self._menuProject.toolbar_items)

        for item in settings.TOOLBAR_ITEMS:
            if item == 'separator':
                self.toolbar.addSeparator()
            else:
                tool_item = toolbar_items.get(item, None)
                if tool_item is not None:
                    self.toolbar.addAction(tool_item)
        #load action added by plugins, This is a special case when reload
        #the toolbar after save the preferences widget
        for toolbar_action in settings.get_toolbar_item_for_plugins():
            self.toolbar.addAction(toolbar_action)

    def load_external_plugins(self, paths):
        for path in paths:
            self.plugin_manager.add_plugin_dir(path)
        #load all plugins!
        self.plugin_manager.discover()
        self.plugin_manager.load_all()

    def show_status_message(self, message):
        self.status.showMessage(message, 2000)

    def load_ui(self, centralWidget):
        #Set Application Font for ToolTips
        QToolTip.setFont(QFont(settings.FONT_FAMILY, 10))
        #Create Main Container to manage Tabs
        self.mainContainer = main_container.MainContainer(self)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
                     self.change_window_title)
        self.connect(self.mainContainer,
                     SIGNAL("locateFunction(QString, QString, bool)"),
                     self.actions.locate_function)
        self.connect(self.mainContainer, SIGNAL("navigateCode(bool, int)"),
                     self.actions.navigate_code_history)
        self.connect(self.mainContainer, SIGNAL("addBackItemNavigation()"),
                     self.actions.add_back_item_navigation)
        self.connect(self.mainContainer, SIGNAL("updateFileMetadata()"),
                     self.actions.update_explorer)
        self.connect(self.mainContainer, SIGNAL("updateLocator(QString)"),
                     self.actions.update_explorer)
        self.connect(self.mainContainer, SIGNAL("openPreferences()"),
                     self._show_preferences)
        self.connect(self.mainContainer, SIGNAL("dontOpenStartPage()"),
                     self._dont_show_start_page_again)
        self.connect(self.mainContainer, SIGNAL("currentTabChanged(QString)"),
                     self.status.handle_tab_changed)
        # Update symbols
        self.connect(self.mainContainer, SIGNAL("updateLocator(QString)"),
                     self.status.explore_file_code)
        #Create Explorer Panel
        self.explorer = explorer_container.ExplorerContainer(self)
        self.connect(self.central, SIGNAL("splitterCentralRotated()"),
                     self.explorer.rotate_tab_position)
        self.connect(self.explorer, SIGNAL("updateLocator()"),
                     self.status.explore_code)
        self.connect(self.explorer, SIGNAL("goToDefinition(int)"),
                     self.actions.editor_go_to_line)
        self.connect(self.explorer, SIGNAL("projectClosed(QString)"),
                     self.actions.close_files_from_project)
        #Create Misc Bottom Container
        self.misc = misc_container.MiscContainer(self)
        self.connect(self.mainContainer, SIGNAL("findOcurrences(QString)"),
                     self.misc.show_find_occurrences)

        centralWidget.insert_central_container(self.mainContainer)
        centralWidget.insert_lateral_container(self.explorer)
        centralWidget.insert_bottom_container(self.misc)
        self.connect(self.mainContainer,
                     SIGNAL("cursorPositionChange(int, int)"),
                     self.central.lateralPanel.update_line_col)
        # TODO: Change current symbol on move
        #self.connect(self.mainContainer,
        #SIGNAL("cursorPositionChange(int, int)"),
        #self.explorer.update_current_symbol)
        self.connect(self.mainContainer, SIGNAL("enabledFollowMode(bool)"),
                     self.central.enable_follow_mode_scrollbar)

        if settings.SHOW_START_PAGE:
            self.mainContainer.show_start_page()

    def _show_preferences(self):
        pref = preferences.PreferencesWidget(self.mainContainer)
        pref.show()

    def _dont_show_start_page_again(self):
        settings.SHOW_START_PAGE = False
        qsettings = QSettings()
        qsettings.beginGroup('preferences')
        qsettings.beginGroup('general')
        qsettings.setValue('showStartPage', settings.SHOW_START_PAGE)
        qsettings.endGroup()
        qsettings.endGroup()
        self.mainContainer.actualTab.close_tab()

    def load_session_files_projects(self,
                                    filesTab1,
                                    filesTab2,
                                    projects,
                                    current_file,
                                    recent_files=None):
        self.mainContainer.open_files(filesTab1, notIDEStart=False)
        self.mainContainer.open_files(filesTab2,
                                      mainTab=False,
                                      notIDEStart=False)
        self.explorer.open_session_projects(projects, notIDEStart=False)
        if current_file:
            self.mainContainer.open_file(current_file, notStart=False)
        if recent_files is not None:
            self._menuFile.update_recent_files(recent_files)

    def open_file(self, filename):
        if filename:
            self.mainContainer.open_file(filename)

    def open_project(self, project):
        if project:
            self.actions.open_project(project)

    def __get_profile(self):
        return self.profile

    def __set_profile(self, profileName):
        self.profile = profileName
        if self.profile is not None:
            self.setWindowTitle('NINJA-IDE (PROFILE: %s)' % self.profile)
        else:
            self.setWindowTitle(
                'NINJA-IDE {Ninja-IDE Is Not Just Another IDE}')

    Profile = property(__get_profile, __set_profile)

    def change_window_title(self, title):
        if self.profile is None:
            self.setWindowTitle('NINJA-IDE - %s' % title)
        else:
            self.setWindowTitle('NINJA-IDE (PROFILE: %s) - %s' %
                                (self.profile, title))
        currentEditor = self.mainContainer.get_actual_editor()
        if currentEditor is not None:
            line = currentEditor.textCursor().blockNumber() + 1
            col = currentEditor.textCursor().columnNumber()
            self.central.lateralPanel.update_line_col(line, col)

    def wheelEvent(self, event):
        if event.modifiers() == Qt.ShiftModifier:
            if event.delta() == 120 and self.opacity < settings.MAX_OPACITY:
                self.opacity += 0.1
            elif event.delta() == -120 and self.opacity > settings.MIN_OPACITY:
                self.opacity -= 0.1
            self.setWindowOpacity(self.opacity)
            event.ignore()
        else:
            QMainWindow.wheelEvent(self, event)

    def save_settings(self):
        """Save the settings before the application is closed with QSettings.

        Info saved: Tabs and projects opened, windows state(size and position).
        """
        qsettings = QSettings()
        editor_widget = self.mainContainer.get_actual_editor()
        current_file = ''
        if editor_widget is not None:
            current_file = editor_widget.ID
        if qsettings.value('preferences/general/loadFiles', 'true') == 'true':
            openedFiles = self.mainContainer.get_opened_documents()
            projects_obj = self.explorer.get_opened_projects()
            projects = [p.path for p in projects_obj]
            qsettings.setValue('openFiles/projects', projects)
            if len(openedFiles) > 0:
                qsettings.setValue('openFiles/mainTab', openedFiles[0])
            if len(openedFiles) == 2:
                qsettings.setValue('openFiles/secondaryTab', openedFiles[1])
            qsettings.setValue('openFiles/currentFile', current_file)
            qsettings.setValue(
                'openFiles/recentFiles',
                self.mainContainer._tabMain.get_recent_files_list())
        qsettings.setValue('preferences/editor/bookmarks', settings.BOOKMARKS)
        qsettings.setValue('preferences/editor/breakpoints',
                           settings.BREAKPOINTS)
        qsettings.setValue('preferences/general/toolbarArea',
                           self.toolBarArea(self.toolbar))
        #Save if the windows state is maximixed
        if (self.isMaximized()):
            qsettings.setValue("window/maximized", True)
        else:
            qsettings.setValue("window/maximized", False)
            #Save the size and position of the mainwindow
            qsettings.setValue("window/size", self.size())
            qsettings.setValue("window/pos", self.pos())
        #Save the size of de splitters
        qsettings.setValue("window/central/areaSize",
                           self.central.get_area_sizes())
        qsettings.setValue("window/central/mainSize",
                           self.central.get_main_sizes())
        #Save the toolbar visibility
        qsettings.setValue("window/hide_toolbar", not self.toolbar.isVisible())
        #Save Profiles
        if self.profile is not None:
            self.actions.save_profile(self.profile)
        else:
            qsettings.setValue('ide/profiles', settings.PROFILES)

    def load_window_geometry(self):
        """Load from QSettings the window size of de Ninja IDE"""
        qsettings = QSettings()
        if qsettings.value("window/maximized", 'true') == 'true':
            self.setWindowState(Qt.WindowMaximized)
        else:
            print dir(QSizeF)

            self.resize(
                qsettings.value("window/size", QSizeF(800, 600)).toSize())
            self.move(
                qsettings.value("window/pos", QPointF(100, 100)).toPoint())

    def closeEvent(self, event):
        if self.s_listener:
            self.s_listener.close()
        if settings.CONFIRM_EXIT and \
        self.mainContainer.check_for_unsaved_tabs():
            unsaved_files = self.mainContainer.get_unsaved_files()
            txt = '\n'.join(unsaved_files)
            val = QMessageBox.question(
                self, self.tr("Some changes were not saved"),
                self.tr("%s\n\nDo you want to exit anyway?" % txt),
                QMessageBox.Yes, QMessageBox.No)
            if val == QMessageBox.No:
                event.ignore()
        QApplication.instance().setCursorFlashTime(cursor_flash_time)
        self.emit(SIGNAL("goingDown()"))
        self.save_settings()
        completion_daemon.shutdown_daemon()
        #close python documentation server (if running)
        self.mainContainer.close_python_doc()
        #Shutdown PluginManager
        self.plugin_manager.shutdown()

    def notify_plugin_errors(self):
        errors = self.plugin_manager.errors
        if errors:
            plugin_error_dialog = traceback_widget.PluginErrorDialog()
            for err_tuple in errors:
                plugin_error_dialog.add_traceback(err_tuple[0], err_tuple[1])
            #show the dialog
            plugin_error_dialog.exec_()
Ejemplo n.º 32
0
class SingletonApp(QApplication):
    
    timeout = 1000
    
    def __init__(self, argv, application_id=None):
        QApplication.__init__(self, argv)
        
        self.socket_filename = unicode(os.path.expanduser("~/.ipc_%s" % self.generate_ipc_id()) )
        self.shared_mem = QSharedMemory()
        self.shared_mem.setKey(self.socket_filename)

        if self.shared_mem.attach():
            self.is_running = True
            return
        
        self.is_running = False
        if not self.shared_mem.create(1):
            print >>sys.stderr, "Unable to create single instance"
            return
        # start local server
        self.server = QLocalServer(self)
        # connect signal for incoming connections
        self.connect(self.server, SIGNAL("newConnection()"), self.receive_message)
        # if socket file exists, delete it
        if os.path.exists(self.socket_filename):
            os.remove(self.socket_filename)
        # listen
        self.server.listen(self.socket_filename)

    def __del__(self):
        self.shared_mem.detach()
        if not self.is_running:
            if os.path.exists(self.socket_filename):
                os.remove(self.socket_filename)
       
    def generate_ipc_id(self, channel=None):
        if channel is None:
            channel = os.path.basename(sys.argv[0])
        return "%s_%s" % (channel, getpass.getuser())

    def send_message(self, message):
        if not self.is_running:
            raise Exception("Client cannot connect to IPC server. Not running.")
        socket = QLocalSocket(self)
        socket.connectToServer(self.socket_filename, QIODevice.WriteOnly)
        if not socket.waitForConnected(self.timeout):
            raise Exception(str(socket.errorString()))
        socket.write(pickle.dumps(message))
        if not socket.waitForBytesWritten(self.timeout):
            raise Exception(str(socket.errorString()))
        socket.disconnectFromServer()
        
    def receive_message(self):
        socket = self.server.nextPendingConnection()
        if not socket.waitForReadyRead(self.timeout):
            print >>sys.stderr, socket.errorString()
            return
        byte_array = socket.readAll()
        self.handle_new_message(pickle.loads(str(byte_array)))

    def handle_new_message(self, message):
        self.emit( SIGNAL("message"), message )