Source

codeaide / codeaide / ide / simple / base.py

Full commit
# -*- coding: utf-8 -*-
import sys
import os

from PyQt4.QtCore import (
   QSettings, QSignalMapper, SIGNAL, QTimer, QVariant)
from PyQt4.QtGui import (
   QApplication, QSplashScreen, qApp, QMainWindow, QTabWidget, QColor, QImage, QPixmap)

   
from codeaide import icon_path
from codeaide.interface import implements, on_hook
from codeaide.ide import api
from codeaide.ide.base import (
   sorted_by_priority, MenuManager, ToolbarManager, StatusbarManager, DockManager)
from codeaide.ide.simple.utils import call_on_idle



class Settings(QSettings):
    implements(api.Settings)

    
    def __init__(self, parent):
        QSettings.__init__(self, parent)

        
    @property
    def keys(self):
        return [unicode(k) for k in self.allKeys()]


    def set(self, key, value):
        self.setValue(key, QVariant(repr(value)))
        self.sync()

    
    def get(self, key, default=None):
        val = self.value(key).toPyObject()
        if not val:
            return default
        try:
            return eval(str(val))
        except Exception, e:
            print key, e, val
            


def app():
    return api.Application.instance


def win():
    return app().active_window


def view():
    return win().active_view


def doc():
    return view().active_document




class Application(QApplication):
    implements(api.Application)

    organisation_name = "cosmos-tools"
    application_name = "codeaide"


    def __init__(self):
        QApplication.__init__(self, sys.argv)
        self.setApplicationName("CodeAide")
        self.setOrganizationName(self.organisation_name)
        self.setApplicationName(self.application_name)
        self.setStyleSheet("QMainWindow::separator { height:2px; width:2px;}")
        #self.connect(self, SIGNAL("lastWindowClosed()"), self._force_quit)
        self.settings = api.Settings(self)
        self._main_window = None


    @property
    def active_window(self):
        return self._main_window

    
    def quit(self, force=False):
        if on_hook(api.OnQuit) and not force:
            return
        self._main_window.close()


    def setup(self):
        self._main_window = self.create_main_window()


    def start(self):
        if on_hook(api.OnStart):
            return False
        if not self._main_window:
            self.setup()
        self._main_window.show()
        if on_hook(api.OnReady):
            return False
        return True


    def run(self):
        if not self._main_window:
            if not self.start():
                return
        if self._main_window:
            return self.exec_()


    def _create_splash(self, show=True):
        splash = QSplashScreen()
        if show:
            img = QImage(os.path.join(icon_path, "splash.png"))
            pm = QPixmap.fromImage(img)
            if not pm.mask():
                if img.hasAlphaBuffer():
                    bm = img.createAlphaMask()
                else:
                    bm = img.createHeuristicMask()
                pm.setMask(bm)
            if pm.mask():
                splash.setMask(pm.mask())
            splash.setPixmap(pm)
            splash.show()
        return splash


    def create_main_window(self):
        self.splash = self._create_splash()
        win = api.MainWindow()
        #self.splash.finish(win)
        QTimer.singleShot(1000, self.splash.close)
        win.setup()
        return win



class MainWindow(QMainWindow):
    implements(api.MainWindow)


    def __init__(self):
        QMainWindow.__init__(self)


    def setup(self):
        self._setup_ui()
        self._restore_settings()


    def _restore_settings(self):
        self.settings = app().settings
        sb = self.settings.get("statusbar", True)
        self.statusBar().setVisible(sb)
        state = self.settings.get("state", None)
        if state:
            self.restoreState(state)
        geom = self.settings.get("geometry", None)
        if geom:
            self.restoreGeometry(geom)
        
            
    def closeEvent(self, event):
        self._view._save_settings()
        self._save_settings()


    def _save_settings(self):
        geom = (self.x(), self.y(), self.width(), self.height())
        self.settings.set("geometry", str(self.saveGeometry()))
        self.settings.set("state", str(self.saveState()))
        self.settings.set("statusbar", self.statusBar().isVisible())


    def _setup_ui(self):
        self.setWindowTitle("[*] %s" % qApp.applicationName())
        self.setDocumentMode(True)
        self.mapper = QSignalMapper(self)
        self.connect(self.mapper, SIGNAL("mappend(QWidget*)"), self.set_active_view)
        self.menu_manager = MenuManager(self.menuBar())
        self.toolbar_manager = ToolbarManager(self)
        self.dock_manager = DockManager(self)
        self.statusbar_manager = StatusbarManager(self)
        self._view = self.create_view()
        self.setCentralWidget(self._view)
        self._setup_commands()
        self._setup_dockwidgets()
        rect = qApp.desktop().availableGeometry(self)
        self.setGeometry(rect)


    def _setup_commands(self):
        self._commands = [
             cmd(self) for cmd in sorted_by_priority(api.Command.implementations)
             ]


    def _setup_dockwidgets(self):
        self._docks = []
        for dock_class in api.Dock.implementations:
            dock = dock_class(self)
            self.dock_manager.add_dockwidget(dock)
            self._docks.append(doc)


    def create_view(self):
        view = api.View(self)
        #call_on_idle(view.open_filename, __file__.rstrip("co"))
        return view


    @property
    def active_view(self):
        return self._view


    
    def set_active_view(self, doc):
        self._view.set_active(doc)




        
class View(QTabWidget):
    implements(api.View)

    def __init__(self, parent):
        QTabWidget.__init__(self)
        call_on_idle(self.setup_ui)
      

    def setup_ui(self):
        self.setDocumentMode(True)
        self.setMovable(True)
        self.setTabsClosable(True)
        self.connect(self, SIGNAL("currentChanged(int)"), self.on_current_changed)
        self.connect(self, SIGNAL("tabCloseRequested(int)"), self.on_close_request)
        self._tabs = []
        self._restore_settings()
        for filename in sys.argv[1:]:
            call_on_idle(self.open_filename, filename)

        
    def _save_settings(self):
        editors = []
        for edit in self._tabs:
            doc = edit.document()
            editors.append(dict(filename=doc.filename, pos=edit.textCursor().position()))
        self.settings.set("editors", editors)
        self.settings.set("active-editor", self.currentIndex())


    def _restore_settings(self):
        self.settings = app().settings
        editors = self.settings.get("editors", [])
        for edit in editors:
            try:
                call_on_idle(self.open_filename, edit["filename"], edit["pos"])
            except Exception, e:
                print e, edit
        if editors:
            try:
                active = self.settings.get("active-editor", 0)
                call_on_idle(self._set_active, active)
            except Exception, e:
                print e, editors
    

    def _set_active(self, i):
        self.setCurrentIndex(i)
        editor = self.currentWidget()
        if editor:
            QTimer.singleShot(500, editor.setFocus)

                
    def on_current_changed(self, i):
        edit = self.currentWidget()
        doc = edit.document()
        self.connect(doc, SIGNAL("modificationChanged(bool)"), self.on_modification_change)
        self.window().setWindowModified(edit.document().isModified())
        self.window().setWindowTitle("")
        self.window().setWindowFilePath(self.tabText(i))
        self.window().emit(SIGNAL("active_document_changed(PyQt_PyObject)"), edit)


    def on_modification_change(self, flag):
        i = self.currentIndex()
        if flag:
            self.tabBar().setTabTextColor(i, QColor("blue"))
        else:
            self.tabBar().setTabTextColor(i, QColor("black"))

        
    @property
    def active_document(self):
        edit = self.currentWidget()
        if edit:
            return edit.document()


    def set_active(self, doc):
        self.setCurrentWidget(doc)

    
    def _new(self, title="unnamed"):
        editor = self._create_editor()
        self._tabs.append(editor)
        self.addTab(editor, title)
        self.setCurrentWidget(editor)
        editor.setFocus()
        editor.new_buffer()
        editor.connect(editor, SIGNAL("cursorPositionChanged()"), self.on_cursor_position_changed)
        return editor


    def _create_editor(self):
        return api.Editor(self)


    def new_filename(self, filename="unnamed.py"):
        editor = self._new(os.path.basename(filename))
        return editor


    def open_filename(self, filename, pos=0):
        if not filename:
            return 
        if not os.path.exists(filename) or os.path.isdir(filename):
            self.statusbar_manager.show_message(i18n("%s does not exist") % filename)
            return
        editor = self._new(os.path.basename(filename))
        editor.load_buffer(filename)
        editor.set_position(pos)
        qApp.processEvents()
        return editor


    def save_filename(self, filename=None):
        filename = filename or self.active_document.filename
        textedit = self.currentWidget()

    
    def on_close_request(self, num):
        edit = self.widget(num)
        #edit.document().close()
        self.removeTab(num)
        del self._tabs[num]


    def on_cursor_position_changed(self):
        textedit = self.currentWidget()
        self.window().statusbar_manager["pos"] = "R%s C%s" % (textedit.row+1, textedit.column+1)


    def close_active(self):
        self.on_close_request(self.currentIndex())

    


        
from codeaide.editors import CodeEditor

class Editor(CodeEditor):
    implements(api.Editor)


    def __init__(self, parent):
        CodeEditor.__init__(self)