Example #1
0
 def showTree(self):
     self.ftree = Tree(self)
     self.treeVis = True
     self.ftree.resize(80,430)
     self.treeSplit.addWidget(self.ftree)
     self.ftree.show()
Example #2
0
 def showTree(self):
     self.ftree = Tree(self)
     self.treeVis = True
     self.ftree.resize(80, 430)
     self.treeSplit.addWidget(self.ftree)
     self.ftree.show()
Example #3
0
class mainWindow(QMainWindow):
    """Class for the main window that contains the tabs, editor, terminal, etc."""

    def __init__(self, parent = None):
        super(mainWindow, self).__init__(parent)
        config.filename = "Untitled"
        self.tabNum = 0
        self.treeVis = False
        self.termVis = False
        config.docList = []
        self.edit = Editor()
        self.editDict = {"edit1":self.edit}
        self.tab = QTabWidget(self)

        self.initUI()

    def writeSettings(self):
        settings = QSettings()
        font = settings.setValue("Editor/font", QVariant(config.font.toString()))
        term = settings.setValue("mainWindow/term", QVariant(self.termVis))
        tree = settings.setValue("mainWindow/tree", QVariant(self.treeVis))
        pDir = settings.setValue("fileTree/proDir", QVariant(config.proDir))

    def readSettings(self):
        # The default fonts represented as a toString() list
        DEFAULT_FONT = str(config.font.family())+",12,-1,5,50,0,0,0,0,0"
        settings = QSettings()
        if config.font.fromString(settings.value("Editor/font",
                                                QVariant(DEFAULT_FONT),type=str)):
            #config.lexer.setDefaultColor(QColor("Black"))
            config.lexer.setFont(config.font)
        self.termVis = settings.value("mainWindow/term", QVariant(False),type=bool)
        self.treeVis = settings.value("mainWindow/tree", QVariant(False),type=bool)
        config.proDir = settings.value("fileTree/proDir",type=str)

    def initActions(self):
        self.newAction = QAction("New Window",self)
        self.newAction.setShortcut("Ctrl+N")
        self.newAction.triggered.connect(self.new)

        self.newTabAction = QAction("New Tab",self)
        self.newTabAction.setShortcut("Ctrl+T")
        self.newTabAction.triggered.connect(self.newTab)

        self.openAction = QAction("Open file",self)
        self.openAction.setShortcut("Ctrl+O")
        self.openAction.triggered.connect(self.openFile)

        self.saveAction = QAction("Save",self)
        self.saveAction.setShortcut("Ctrl+S")
        self.saveAction.triggered.connect(self.saveFile)

        self.saveasAction = QAction("Save As",self)
        self.saveasAction.setShortcut("Ctrl+Shift+S")
        self.saveasAction.triggered.connect(self.saveFileAs)

        self.cutAction = QAction("Cut",self)
        self.cutAction.setShortcut("Ctrl+X")
        self.cutAction.triggered.connect(lambda cut:
                                         self.getEditor(self.tab.currentIndex()).cut)

        self.copyAction = QAction("Copy",self)
        self.copyAction.setShortcut("Ctrl+C")
        self.copyAction.triggered.connect(lambda copy:
                                          self.getEditor(self.tab.currentIndex()).copy)

        self.pasteAction = QAction("Paste",self)
        self.pasteAction.setShortcut("Ctrl+V")
        self.pasteAction.triggered.connect(lambda paste:
                                           self.getEditor(self.tab.currentIndex()).paste)

        self.undoAction = QAction("Undo",self)
        self.undoAction.setShortcut("Ctrl+Z")
        self.undoAction.triggered.connect(lambda undo:
                                          self.getEditor(self.tab.currentIndex()).undo)

        self.redoAction = QAction("Redo",self)
        self.redoAction.setShortcut("Ctrl+Y")
        self.redoAction.triggered.connect(lambda redo:
                                          self.getEditor(self.tab.currentIndex()).redo)

        self.aboutAction = QAction("About Codex",self)
        self.aboutAction.triggered.connect(self.about)

        self.noLexAct = QAction("Plain Text",self)
        self.noLexAct.triggered.connect(lambda noLex:
                                        self.getEditor(self.tab.currentIndex()).\
                                        setLexer(QsciLexerText()))

        self.termAct = QAction("Terminal",self)
        self.termAct.setCheckable(True)
        self.termAct.triggered.connect(self.toggleTerm)

        self.treeAct = QAction("File Tree",self)
        self.treeAct.setCheckable(True)
        self.treeAct.triggered.connect(self.toggleTree)

        self.toggleIntAct = QAction("Indentation Guides",self)
        self.toggleIntAct.triggered.connect(self.toggleIntGuide)
        self.toggleIntAct.setCheckable(True)
        self.toggleIntAct.setChecked(True)

        self.toggleLNAct = QAction("Line Numbers",self)
        self.toggleLNAct.triggered.connect(self.toggleLN)
        self.toggleLNAct.setCheckable(True)
        self.toggleLNAct.setChecked(True)

        self.FRAct = QAction("Find and Replace",self)
        self.FRAct.triggered.connect(self.fr)
        self.FRAct.setShortcut("Ctrl+F")

        self.fontAct = QAction("Choose Font",self)
        self.fontAct.triggered.connect(self.chooseFont)

        self.dirAct = QAction("Choose Project Directory",self)
        self.dirAct.triggered.connect(self.setProDir)

    def getEditor(self, index):
        if index == 0:
            return self.editDict.get("edit1")
        else:
            return self.editDict.get(("edit"+str(index)))

    def getCurrentFile(self):
        return config.docList[self.tab.currentIndex()] # returns tuple (?)

    def initMenubar(self):
        menubar = self.menuBar()

        file = menubar.addMenu("File")
        edit = menubar.addMenu("Edit")
        self.lang = menubar.addMenu("Languages")
        view = menubar.addMenu("View")
        about = menubar.addMenu("About")

        self.initLexers()

        file.addAction(self.newAction)
        file.addAction(self.newTabAction)
        file.addAction(self.openAction)
        file.addAction(self.saveAction)
        file.addAction(self.saveasAction)
        file.addSeparator()
        file.addAction(self.fontAct)
        file.addAction(self.dirAct)

        edit.addAction(self.undoAction)
        edit.addAction(self.redoAction)
        edit.addSeparator()
        edit.addAction(self.copyAction)
        edit.addAction(self.cutAction)
        edit.addAction(self.pasteAction)
        edit.addAction(self.FRAct)

        view.addAction(self.termAct)
        view.addAction(self.toggleIntAct)
        view.addAction(self.toggleLNAct)
        view.addAction(self.treeAct)

        about.addAction(self.aboutAction)

    def lessTabs(self):
        self.tabNum = self.tabNum - 1
        try:
            #print config.docList
            config.docList.remove(config.docList[self.tab.currentIndex()-1])
        except:
            if len(config.docList) == 0:
                pass
        finally:
            if self.tabNum < 1:
                self.newTab()
            else:
                self.tab.removeTab(self.tab.currentIndex()-1)
            #print self.tabNum

    def initTabs(self):
        # Set up the tabs
        self.tab.tabCloseRequested.connect(self.tab.removeTab)
        self.tab.tabCloseRequested.connect(self.lessTabs)
        self.tab.setMovable(True)
        # Needed for Mac
        self.tab.setDocumentMode(True)
        self.setUnifiedTitleAndToolBarOnMac(True)
        # Automatically make new tabs contain an editor widget
        self.tab.addTab(self.editDict.get("edit1"), config.filename)
        self.termSplit.addWidget(self.tab)
        self.tab.setTabsClosable(True)

    def initUI(self):
        # Create first qsplitter for sidebar
        self.treeSplit = QSplitter()
        self.treeSplit.setOrientation(Qt.Horizontal)
        # Create second qsplitter (Allows split screen for terminal)
        self.termSplit = QSplitter()
        self.termSplit.setOrientation(Qt.Vertical)
        # Add a termSplit to the treeSplit
        self.treeSplit.addWidget(self.termSplit)
        self.setCentralWidget(self.treeSplit)
        # Create everything else
        self.initTabs()
        self.initActions()
        self.initMenubar()
        # Create terminal widget and automatically hide it because otherwise
        # it will awkwardly hover in the corner
        self.term = Terminal()
        #self.term.hide()
        # x and y coordinates on the screen, width, height
        self.setGeometry(100,100,800,630)
        self.setWindowTitle("Codex")
        # Move up to the parent directory and set the window icons.
        # Without os.path it will look for icons in src/
        self.setWindowIcon(QIcon(os.path.join(
        os.path.dirname(__file__)) + "/icons/256x256/codex.png"))
        # Open any documents that were open before closing and restore settings
        QTimer.singleShot(0,self.loadDocs)
        self.readSettings()
        # Show the terminal/tree if necessary.
        self.loadTermAndTree()
        # If there are no documents to load set the language as plain text
        # If there are documents to load guess lexers for them
        if len(config.docList) == 0:
            self.getEditor(self.tabNum).setLang(QsciLexerText())
            self.noLexAct.setChecked(True)
        else:
            self.guessLexer()
        # Set font
        self.getEditor(self.tab.currentIndex()).lexer.setFont(config.font)

    def initLexers(self):
        # Dict that maps lexer actions to their respective strings
        self.lexActs = {}
        langGrp = QActionGroup(self.lang)
        langGrp.setExclusive(True)
        self.lang.addAction(self.noLexAct)
        self.noLexAct.setCheckable(True)
        #self.noLexAct.setChecked(True)
        self.noLexAct.setActionGroup(langGrp)
        self.lang.addSeparator()
        languages = sorted(config.LEXERS.keys())
        for i in languages:
            langAct = self.lang.addAction(i)
            langAct.setCheckable(True)
            langAct.setActionGroup(langGrp)
            self.lexActs[langAct] = i
        langGrp.triggered.connect(lambda lex: self.getEditor(self.tabNum+1).setLang(self.lexActs.get(lex)))

    def guessLexer(self):
        try:
            x = config.docList[self.tab.currentIndex()+1]
            n, e = os.path.basename(x).lower().split(".")
            if e == "sh" or e == "bsh":
                self.getEditor(self.tabNum).setLang("Bash")
            elif e == "cmd" or e == "bat" or e == "btm" or e == "nt":
                self.getEditor(self.tabNum).setLang("Batch")
            elif e == "cmake" or e == "cmakelists":
                self.getEditor(self.tabNum).setLang("CMake")
            elif e == "cpp" or e == "cxx" or e == "cc" or e == "c" or e == "h"\
            or e == "hh" or e == "hpp":
                self.getEditor(self.tabNum).setLang("C++")
            elif e == "cs":
                self.getEditor(self.tabNum).setLang("C#")
            elif e == "css":
                self.getEditor(self.tabNum).setLang("CSS")
            elif e == "d":
                self.getEditor(self.tabNum).setLang("D")
            elif e == "diff" or e == "patch":
                self.getEditor(self.tabNum).setLang("Diff")
            elif e == "f90" or e == "f95" or e == "f2k" or e == "f03" or e == "f15":
                self.getEditor(self.tabNum).setLang("Fortran")
            elif e == "f" or e == "for":
                self.getEditor(self.tabNum).setLang("Fortran77")
            elif e == "html" or e == "htm":
                self.getEditor(self.tabNum).setLang("HTML")
            elif e == "java":
                self.getEditor(self.tabNum).setLang("Java")
            elif e == "js":
                self.getEditor(self.tabNum).setLang("JavaScript")
            elif e == "lua":
                self.getEditor(self.tabNum).setLang("Lua")
            elif e == "mak" or n == "gnumakefile" or n == "makefile":
                self.getEditor(self.tabNum).setLang("Makefile")
            elif e == "m":
                self.getEditor(self.tabNum).setLang("MATLAB")
            elif e == "pas" or e == "inc":
                self.getEditor(self.tabNum).setLang("Pascal")
            elif e == "ps":
                self.getEditor(self.tabNum).setLang("PostScript")
            elif e == "pov" or e == "tga":
                self.getEditor(self.tabNum).setLang("POV-Ray")
            elif e == "py" or e == "pyw":
                self.getEditor(self.tabNum).setLang("Python")
                #print "p"
            elif e == "rb" or e == "rbw":
                self.getEditor(self.tabNum).setLang("Ruby")
            elif e == "cir":
                self.getEditor(self.tabNum).setLang("Spice")
            elif e == "sql":
                self.getEditor(self.tabNum).setLang("SQL")
            elif e == "tcl":
                self.getEditor(self.tabNum).setLang("TCL")
            elif e == "tex":
                self.getEditor(self.tabNum).setLang("TeX")
            elif e == "v" or e == "sv" or e == "vh" or e == "svh":
                self.getEditor(self.tabNum).setLang("Verilog")
            elif e == "vhd" or e == "vhdl":
                self.getEditor(self.tabNum).setLang("VHDL")
            elif e == "xml" or e == "xsl" or e == "xsml" or e == "xsd" or \
            e == "kml" or e == "wsdl" or e == "xlf" or e == "xliff":
                self.getEditor(self.tabNum).setLang("XML")
            elif e == "yml":
                self.getEditor(self.tabNum).setLang("YML")
        except (ValueError, IndexError):
                self.lexer = QsciLexerText()
                self.lexer.setDefaultFont(config.font)
                self.lexer.setDefaultColor(QColor("Black"))
                self.getEditor(self.tabNum).setLexer(self.lexer)
                self.noLexAct.setChecked(True)

    def new(self):
        main = mainWindow()
        main.show()

    def open(self):
        index = self.tab.currentIndex()
        if(self.file != ('', '')):
            with open(self.file, "rt") as f:
                if self.tabNum >= 1:
                    self.newEditor()
                    #print "t"
                    self.tab.setTabText(index+1, os.path.basename(str(self.file)))
                    self.getEditor(self.tabNum).setText(f.read())
                    self.tab.setCurrentIndex(index+1)
                if self.tabNum == 0:
                    self.tabNum = 1
                    self.tab.setTabText(index, os.path.basename(str(self.file)))
                    #print(self.tabNum)
                    self.getEditor(self.tabNum).setText(f.read())
                    self.tab.setCurrentIndex(index+1)
        # Try to guess the lexer based on extension
        self.guessLexer()
        # Not really sure where else to put this
        self.getEditor(self.tab.currentIndex()+1).setModified(False)
        self.getEditor(self.tabNum).textChanged.connect(self.unsaved)

    def newEditor(self):
        self.tabNum+=1
        # Add a new entry to the dict and map it an editor object
        self.editDict["edit"+str(self.tabNum)] = Editor()
        self.tab.addTab(self.getEditor(self.tabNum),
                        os.path.basename(str(self.file)))
        #print "o"

    def openFile(self):
        self.file = QFileDialog.getOpenFileName(self, 'Open File',".")[0]
        try:
            config.docList.append(str(self.file))
            #print "k"
            self.open()
        except AttributeError:
            config.docList.append(str(self.file))
            self.open()
            #print "h"

    def loadDocs(self):
        fh = None
        if not os.access(".open.p", os.F_OK):
            return
        else:
            try:
                fh = gzip.open(".open.p", "rb")
                config.docList = pickle.load(fh)
                for x in config.docList:
                    self.file = x
                    self.open()
            except (IOError, OSError):
                #print e
                return
            finally:
                if fh is not None:
                    fh.close()

    def save(self):
        # Save the file as plain text
        with open(self.getCurrentFile(), "wt") as file:
            file.write(self.getEditor(self.tab.currentIndex()+1).text())
        # Note that changes to the document are saved
        self.edit.setModified(False)
        # Set the tab title to filename
        self.tab.setTabText(self.tab.currentIndex(),
                            os.path.basename(str(self.getCurrentFile())))

    def saveDocs(self):
        try:
            fh = gzip.open(".open.p", "wb")
            pickle.dump(config.docList, fh, 2)
        except (IOError, OSError) as e:
            raise e
        finally:
            if fh:
                fh.close()

    def saveFile(self):
        # Only open if it hasn't previously been saved
        if len(config.docList) != 0:
            if self.getCurrentFile() == "Untitled":
                config.docList[self.tab.currentIndex()] = \
                QFileDialog.getSaveFileName(self, 'Save File')
            self.save()
        else:
            config.docList.append(QFileDialog.getSaveFileName
                                  (self, 'Save File'))
            self.save()

    def saveFileAs(self):
        config.filename = QFileDialog.getSaveFileName(self, 'Save File')
        self.save()

    def unsaved(self):
        if self.getEditor(self.tab.currentIndex()+1).isModified:
            self.tab.setTabText(self.tab.currentIndex(),
                                os.path.basename(self.getCurrentFile()+"*"))

    def about(self):
        QMessageBox.about(self, "About Codex",
                                "<p>Codex is a text editor for programmers " \
                                "made with PyQt5 and QScintilla.</p>"
                                )

    def toggleTabs(self):
        state = self.tab.isVisible()
        self.tab.setVisible(not state)

    def newTab(self):
        self.tabNum+=1
        # Add a new entry to the dict and map it to an editor object
        self.editDict["edit"+str(self.tabNum)] = Editor()
        self.tab.addTab(self.getEditor(self.tabNum),
                        "Untitled")
        self.guessLexer()
        self.getEditor(self.tab.currentIndex()+1).lexer.setFont(config.font)

    def showTerm(self):
        self.termVis = True
        self.termSplit.addWidget(self.term)
        self.term.resize(800,40)
        self.term.setFont(config.font)
        self.term.show()

    def hideTerm(self):
        self.termVis = False
        self.term.hide()

    def toggleTerm(self):
        self.hideTerm() if self.termVis else self.showTerm()

    def showTree(self):
        self.ftree = Tree(self)
        self.treeVis = True
        self.ftree.resize(80,430)
        self.treeSplit.addWidget(self.ftree)
        self.ftree.show()

    def hideTree(self):
        self.treeVis = False
        self.ftree.close()

    def toggleTree(self):
        self.hideTree() if self.treeVis else self.showTree()

    def loadTermAndTree(self):
        if self.treeVis:
            self.showTree()
            self.treeAct.setChecked(True)
        else:
            self.treeVis = False
            self.treeAct.setChecked(False)
        if self.termVis:
            self.showTerm()
            self.termAct.setChecked(True)
        else:
            self.termVis = False
            self.termAct.setChecked(False)

    def toggleIntGuide(self):
        state = self.edit.indentationGuides()
        self.edit.setIndentationGuides(not state)

    def toggleLN(self):
        state = self.edit.marginLineNumbers(0)
        self.edit.setMarginLineNumbers(0, not state)
        self.edit.setMarginWidth(0,0) if state == True else self.edit. \
                                setMarginWidth(0,self.edit.metrics.width("00000"))

    def fr(self):
        frwin = Find(self)
        frwin.show()

    def chooseFont(self):
        font, ok = QFontDialog.getFont()
        if ok:
            config.font = font
            try:
                self.getEditor(self.tab.currentIndex()).lexer().setFont(config.font)
            except AttributeError:
                self.getEditor(self.tab.currentIndex()).setLang(QsciLexerText())
                #print self.getEditor(self.tab.currentIndex()).lexer()
                self.getEditor(self.tab.currentIndex()).lexer().setFont(config.font)

    def setProDir(self):
        pdir, ok = QInputDialog.getText(self, "Set Project Directory",
                                             "Enter absolute path (i.e. "\
                                             "/home/steve/Documents)")
        if ok:
            config.proDir = pdir
            #print config.proDir


    # This method adapted from Peter Goldsborough's Writer.
    # Save settings and alerts the user if they are saving an edited file.
    def closeEvent(self,event):
        self.writeSettings()
        self.saveDocs()
        if not self.edit.isModified():
            event.accept()
        else:
            dialog = QMessageBox(self)
            dialog.setIcon(QMessageBox.Warning)
            dialog.setText(config.filename+" has unsaved changes.")
            dialog.setInformativeText("Do you want to save your changes?")
            dialog.setStandardButtons(QMessageBox.Save |
                                  QMessageBox.Cancel |
                                  QMessageBox.Discard)
            dialog.setDefaultButton(QMessageBox.Save)
            response = dialog.exec_()
            if response == QMessageBox.Save:
                self.save()
            elif response == QMessageBox.Discard:
                event.accept()
            else: event.ignore()

    def resizeEvent(self,event):
        # Don't try to resize a non-existant file tree
        try:
            self.ftree.treeView.resize(self.ftree.treeView.width(), self.height())
        except:
            pass
        try:
            self.term.resize(self.width(), self.term.height())
        except:
            pass

    def keyPressEvent(self,event):
        key = event.key()
        if (self.getEditor(self.tab.currentIndex()).text() == "bee movie"):
            with open("bee_movie.txt", "r") as file:
                script = file.read()
            self.getEditor(self.tab.currentIndex()).setText(script)
Example #4
0
class mainWindow(QMainWindow):
    """Class for the main window that contains the tabs, editor, terminal, etc."""
    def __init__(self, parent=None):
        super(mainWindow, self).__init__(parent)
        config.filename = "Untitled"
        self.tabNum = 0
        self.treeVis = False
        self.termVis = False
        config.docList = []
        self.edit = Editor()
        self.editDict = {"edit1": self.edit}
        self.tab = QTabWidget(self)

        self.initUI()

    def writeSettings(self):
        settings = QSettings()
        font = settings.setValue("Editor/font",
                                 QVariant(config.font.toString()))
        term = settings.setValue("mainWindow/term", QVariant(self.termVis))
        tree = settings.setValue("mainWindow/tree", QVariant(self.treeVis))
        pDir = settings.setValue("fileTree/proDir", QVariant(config.proDir))

    def readSettings(self):
        # The default fonts represented as a toString() list
        DEFAULT_FONT = str(config.font.family()) + ",12,-1,5,50,0,0,0,0,0"
        settings = QSettings()
        if config.font.fromString(
                settings.value("Editor/font", QVariant(DEFAULT_FONT),
                               type=str)):
            #config.lexer.setDefaultColor(QColor("Black"))
            config.lexer.setFont(config.font)
        self.termVis = settings.value("mainWindow/term",
                                      QVariant(False),
                                      type=bool)
        self.treeVis = settings.value("mainWindow/tree",
                                      QVariant(False),
                                      type=bool)
        config.proDir = settings.value("fileTree/proDir", type=str)

    def initActions(self):
        self.newAction = QAction("New Window", self)
        self.newAction.setShortcut("Ctrl+N")
        self.newAction.triggered.connect(self.new)

        self.newTabAction = QAction("New Tab", self)
        self.newTabAction.setShortcut("Ctrl+T")
        self.newTabAction.triggered.connect(self.newTab)

        self.openAction = QAction("Open file", self)
        self.openAction.setShortcut("Ctrl+O")
        self.openAction.triggered.connect(self.openFile)

        self.saveAction = QAction("Save", self)
        self.saveAction.setShortcut("Ctrl+S")
        self.saveAction.triggered.connect(self.saveFile)

        self.saveasAction = QAction("Save As", self)
        self.saveasAction.setShortcut("Ctrl+Shift+S")
        self.saveasAction.triggered.connect(self.saveFileAs)

        self.cutAction = QAction("Cut", self)
        self.cutAction.setShortcut("Ctrl+X")
        self.cutAction.triggered.connect(
            lambda cut: self.getEditor(self.tab.currentIndex()).cut)

        self.copyAction = QAction("Copy", self)
        self.copyAction.setShortcut("Ctrl+C")
        self.copyAction.triggered.connect(
            lambda copy: self.getEditor(self.tab.currentIndex()).copy)

        self.pasteAction = QAction("Paste", self)
        self.pasteAction.setShortcut("Ctrl+V")
        self.pasteAction.triggered.connect(
            lambda paste: self.getEditor(self.tab.currentIndex()).paste)

        self.undoAction = QAction("Undo", self)
        self.undoAction.setShortcut("Ctrl+Z")
        self.undoAction.triggered.connect(
            lambda undo: self.getEditor(self.tab.currentIndex()).undo)

        self.redoAction = QAction("Redo", self)
        self.redoAction.setShortcut("Ctrl+Y")
        self.redoAction.triggered.connect(
            lambda redo: self.getEditor(self.tab.currentIndex()).redo)

        self.aboutAction = QAction("About Codex", self)
        self.aboutAction.triggered.connect(self.about)

        self.noLexAct = QAction("Plain Text", self)
        self.noLexAct.triggered.connect(lambda noLex:
                                        self.getEditor(self.tab.currentIndex()).\
                                        setLexer(QsciLexerText()))

        self.termAct = QAction("Terminal", self)
        self.termAct.setCheckable(True)
        self.termAct.triggered.connect(self.toggleTerm)

        self.treeAct = QAction("File Tree", self)
        self.treeAct.setCheckable(True)
        self.treeAct.triggered.connect(self.toggleTree)

        self.toggleIntAct = QAction("Indentation Guides", self)
        self.toggleIntAct.triggered.connect(self.toggleIntGuide)
        self.toggleIntAct.setCheckable(True)
        self.toggleIntAct.setChecked(True)

        self.toggleLNAct = QAction("Line Numbers", self)
        self.toggleLNAct.triggered.connect(self.toggleLN)
        self.toggleLNAct.setCheckable(True)
        self.toggleLNAct.setChecked(True)

        self.FRAct = QAction("Find and Replace", self)
        self.FRAct.triggered.connect(self.fr)
        self.FRAct.setShortcut("Ctrl+F")

        self.fontAct = QAction("Choose Font", self)
        self.fontAct.triggered.connect(self.chooseFont)

        self.dirAct = QAction("Choose Project Directory", self)
        self.dirAct.triggered.connect(self.setProDir)

    def getEditor(self, index):
        if index == 0:
            return self.editDict.get("edit1")
        else:
            return self.editDict.get(("edit" + str(index)))

    def getCurrentFile(self):
        return config.docList[self.tab.currentIndex()]  # returns tuple (?)

    def initMenubar(self):
        menubar = self.menuBar()

        file = menubar.addMenu("File")
        edit = menubar.addMenu("Edit")
        self.lang = menubar.addMenu("Languages")
        view = menubar.addMenu("View")
        about = menubar.addMenu("About")

        self.initLexers()

        file.addAction(self.newAction)
        file.addAction(self.newTabAction)
        file.addAction(self.openAction)
        file.addAction(self.saveAction)
        file.addAction(self.saveasAction)
        file.addSeparator()
        file.addAction(self.fontAct)
        file.addAction(self.dirAct)

        edit.addAction(self.undoAction)
        edit.addAction(self.redoAction)
        edit.addSeparator()
        edit.addAction(self.copyAction)
        edit.addAction(self.cutAction)
        edit.addAction(self.pasteAction)
        edit.addAction(self.FRAct)

        view.addAction(self.termAct)
        view.addAction(self.toggleIntAct)
        view.addAction(self.toggleLNAct)
        view.addAction(self.treeAct)

        about.addAction(self.aboutAction)

    def lessTabs(self):
        self.tabNum = self.tabNum - 1
        try:
            #print config.docList
            config.docList.remove(config.docList[self.tab.currentIndex() - 1])
        except:
            if len(config.docList) == 0:
                pass
        finally:
            if self.tabNum < 1:
                self.newTab()
            else:
                self.tab.removeTab(self.tab.currentIndex() - 1)
            #print self.tabNum

    def initTabs(self):
        # Set up the tabs
        self.tab.tabCloseRequested.connect(self.tab.removeTab)
        self.tab.tabCloseRequested.connect(self.lessTabs)
        self.tab.setMovable(True)
        # Needed for Mac
        self.tab.setDocumentMode(True)
        self.setUnifiedTitleAndToolBarOnMac(True)
        # Automatically make new tabs contain an editor widget
        self.tab.addTab(self.editDict.get("edit1"), config.filename)
        self.termSplit.addWidget(self.tab)
        self.tab.setTabsClosable(True)

    def initUI(self):
        # Create first qsplitter for sidebar
        self.treeSplit = QSplitter()
        self.treeSplit.setOrientation(Qt.Horizontal)
        # Create second qsplitter (Allows split screen for terminal)
        self.termSplit = QSplitter()
        self.termSplit.setOrientation(Qt.Vertical)
        # Add a termSplit to the treeSplit
        self.treeSplit.addWidget(self.termSplit)
        self.setCentralWidget(self.treeSplit)
        # Create everything else
        self.initTabs()
        self.initActions()
        self.initMenubar()
        # Create terminal widget and automatically hide it because otherwise
        # it will awkwardly hover in the corner
        self.term = Terminal()
        #self.term.hide()
        # x and y coordinates on the screen, width, height
        self.setGeometry(100, 100, 800, 630)
        self.setWindowTitle("Codex")
        # Move up to the parent directory and set the window icons.
        # Without os.path it will look for icons in src/
        self.setWindowIcon(
            QIcon(
                os.path.join(os.path.dirname(__file__)) +
                "/icons/256x256/codex.png"))
        # Open any documents that were open before closing and restore settings
        QTimer.singleShot(0, self.loadDocs)
        self.readSettings()
        # Show the terminal/tree if necessary.
        self.loadTermAndTree()
        # If there are no documents to load set the language as plain text
        # If there are documents to load guess lexers for them
        if len(config.docList) == 0:
            self.getEditor(self.tabNum).setLang(QsciLexerText())
            self.noLexAct.setChecked(True)
        else:
            self.guessLexer()
        # Set font
        self.getEditor(self.tab.currentIndex()).lexer.setFont(config.font)

    def initLexers(self):
        # Dict that maps lexer actions to their respective strings
        self.lexActs = {}
        langGrp = QActionGroup(self.lang)
        langGrp.setExclusive(True)
        self.lang.addAction(self.noLexAct)
        self.noLexAct.setCheckable(True)
        #self.noLexAct.setChecked(True)
        self.noLexAct.setActionGroup(langGrp)
        self.lang.addSeparator()
        languages = sorted(config.LEXERS.keys())
        for i in languages:
            langAct = self.lang.addAction(i)
            langAct.setCheckable(True)
            langAct.setActionGroup(langGrp)
            self.lexActs[langAct] = i
        langGrp.triggered.connect(lambda lex: self.getEditor(self.tabNum + 1).
                                  setLang(self.lexActs.get(lex)))

    def guessLexer(self):
        try:
            x = config.docList[self.tab.currentIndex() + 1]
            n, e = os.path.basename(x).lower().split(".")
            if e == "sh" or e == "bsh":
                self.getEditor(self.tabNum).setLang("Bash")
            elif e == "cmd" or e == "bat" or e == "btm" or e == "nt":
                self.getEditor(self.tabNum).setLang("Batch")
            elif e == "cmake" or e == "cmakelists":
                self.getEditor(self.tabNum).setLang("CMake")
            elif e == "cpp" or e == "cxx" or e == "cc" or e == "c" or e == "h"\
            or e == "hh" or e == "hpp":
                self.getEditor(self.tabNum).setLang("C++")
            elif e == "cs":
                self.getEditor(self.tabNum).setLang("C#")
            elif e == "css":
                self.getEditor(self.tabNum).setLang("CSS")
            elif e == "d":
                self.getEditor(self.tabNum).setLang("D")
            elif e == "diff" or e == "patch":
                self.getEditor(self.tabNum).setLang("Diff")
            elif e == "f90" or e == "f95" or e == "f2k" or e == "f03" or e == "f15":
                self.getEditor(self.tabNum).setLang("Fortran")
            elif e == "f" or e == "for":
                self.getEditor(self.tabNum).setLang("Fortran77")
            elif e == "html" or e == "htm":
                self.getEditor(self.tabNum).setLang("HTML")
            elif e == "java":
                self.getEditor(self.tabNum).setLang("Java")
            elif e == "js":
                self.getEditor(self.tabNum).setLang("JavaScript")
            elif e == "lua":
                self.getEditor(self.tabNum).setLang("Lua")
            elif e == "mak" or n == "gnumakefile" or n == "makefile":
                self.getEditor(self.tabNum).setLang("Makefile")
            elif e == "m":
                self.getEditor(self.tabNum).setLang("MATLAB")
            elif e == "pas" or e == "inc":
                self.getEditor(self.tabNum).setLang("Pascal")
            elif e == "ps":
                self.getEditor(self.tabNum).setLang("PostScript")
            elif e == "pov" or e == "tga":
                self.getEditor(self.tabNum).setLang("POV-Ray")
            elif e == "py" or e == "pyw":
                self.getEditor(self.tabNum).setLang("Python")
                #print "p"
            elif e == "rb" or e == "rbw":
                self.getEditor(self.tabNum).setLang("Ruby")
            elif e == "cir":
                self.getEditor(self.tabNum).setLang("Spice")
            elif e == "sql":
                self.getEditor(self.tabNum).setLang("SQL")
            elif e == "tcl":
                self.getEditor(self.tabNum).setLang("TCL")
            elif e == "tex":
                self.getEditor(self.tabNum).setLang("TeX")
            elif e == "v" or e == "sv" or e == "vh" or e == "svh":
                self.getEditor(self.tabNum).setLang("Verilog")
            elif e == "vhd" or e == "vhdl":
                self.getEditor(self.tabNum).setLang("VHDL")
            elif e == "xml" or e == "xsl" or e == "xsml" or e == "xsd" or \
            e == "kml" or e == "wsdl" or e == "xlf" or e == "xliff":
                self.getEditor(self.tabNum).setLang("XML")
            elif e == "yml":
                self.getEditor(self.tabNum).setLang("YML")
        except (ValueError, IndexError):
            self.lexer = QsciLexerText()
            self.lexer.setDefaultFont(config.font)
            self.lexer.setDefaultColor(QColor("Black"))
            self.getEditor(self.tabNum).setLexer(self.lexer)
            self.noLexAct.setChecked(True)

    def new(self):
        main = mainWindow()
        main.show()

    def open(self):
        index = self.tab.currentIndex()
        if (self.file != ('', '')):
            with open(self.file, "rt") as f:
                if self.tabNum >= 1:
                    self.newEditor()
                    #print "t"
                    self.tab.setTabText(index + 1,
                                        os.path.basename(str(self.file)))
                    self.getEditor(self.tabNum).setText(f.read())
                    self.tab.setCurrentIndex(index + 1)
                if self.tabNum == 0:
                    self.tabNum = 1
                    self.tab.setTabText(index,
                                        os.path.basename(str(self.file)))
                    #print(self.tabNum)
                    self.getEditor(self.tabNum).setText(f.read())
                    self.tab.setCurrentIndex(index + 1)
        # Try to guess the lexer based on extension
        self.guessLexer()
        # Not really sure where else to put this
        self.getEditor(self.tab.currentIndex() + 1).setModified(False)
        self.getEditor(self.tabNum).textChanged.connect(self.unsaved)

    def newEditor(self):
        self.tabNum += 1
        # Add a new entry to the dict and map it an editor object
        self.editDict["edit" + str(self.tabNum)] = Editor()
        self.tab.addTab(self.getEditor(self.tabNum),
                        os.path.basename(str(self.file)))
        #print "o"

    def openFile(self):
        self.file = QFileDialog.getOpenFileName(self, 'Open File', ".")[0]
        try:
            config.docList.append(str(self.file))
            #print "k"
            self.open()
        except AttributeError:
            config.docList.append(str(self.file))
            self.open()
            #print "h"

    def loadDocs(self):
        fh = None
        if not os.access(".open.p", os.F_OK):
            return
        else:
            try:
                fh = gzip.open(".open.p", "rb")
                config.docList = pickle.load(fh)
                for x in config.docList:
                    self.file = x
                    self.open()
            except (IOError, OSError):
                #print e
                return
            finally:
                if fh is not None:
                    fh.close()

    def save(self):
        # Save the file as plain text
        with open(self.getCurrentFile(), "wt") as file:
            file.write(self.getEditor(self.tab.currentIndex() + 1).text())
        # Note that changes to the document are saved
        self.edit.setModified(False)
        # Set the tab title to filename
        self.tab.setTabText(self.tab.currentIndex(),
                            os.path.basename(str(self.getCurrentFile())))

    def saveDocs(self):
        try:
            fh = gzip.open(".open.p", "wb")
            pickle.dump(config.docList, fh, 2)
        except (IOError, OSError) as e:
            raise e
        finally:
            if fh:
                fh.close()

    def saveFile(self):
        # Only open if it hasn't previously been saved
        if len(config.docList) != 0:
            if self.getCurrentFile() == "Untitled":
                config.docList[self.tab.currentIndex()] = \
                QFileDialog.getSaveFileName(self, 'Save File')
            self.save()
        else:
            config.docList.append(
                QFileDialog.getSaveFileName(self, 'Save File'))
            self.save()

    def saveFileAs(self):
        config.filename = QFileDialog.getSaveFileName(self, 'Save File')
        self.save()

    def unsaved(self):
        if self.getEditor(self.tab.currentIndex() + 1).isModified:
            self.tab.setTabText(self.tab.currentIndex(),
                                os.path.basename(self.getCurrentFile() + "*"))

    def about(self):
        QMessageBox.about(self, "About Codex",
                                "<p>Codex is a text editor for programmers " \
                                "made with PyQt5 and QScintilla.</p>"
                                )

    def toggleTabs(self):
        state = self.tab.isVisible()
        self.tab.setVisible(not state)

    def newTab(self):
        self.tabNum += 1
        # Add a new entry to the dict and map it to an editor object
        self.editDict["edit" + str(self.tabNum)] = Editor()
        self.tab.addTab(self.getEditor(self.tabNum), "Untitled")
        self.guessLexer()
        self.getEditor(self.tab.currentIndex() + 1).lexer.setFont(config.font)

    def showTerm(self):
        self.termVis = True
        self.termSplit.addWidget(self.term)
        self.term.resize(800, 40)
        self.term.setFont(config.font)
        self.term.show()

    def hideTerm(self):
        self.termVis = False
        self.term.hide()

    def toggleTerm(self):
        self.hideTerm() if self.termVis else self.showTerm()

    def showTree(self):
        self.ftree = Tree(self)
        self.treeVis = True
        self.ftree.resize(80, 430)
        self.treeSplit.addWidget(self.ftree)
        self.ftree.show()

    def hideTree(self):
        self.treeVis = False
        self.ftree.close()

    def toggleTree(self):
        self.hideTree() if self.treeVis else self.showTree()

    def loadTermAndTree(self):
        if self.treeVis:
            self.showTree()
            self.treeAct.setChecked(True)
        else:
            self.treeVis = False
            self.treeAct.setChecked(False)
        if self.termVis:
            self.showTerm()
            self.termAct.setChecked(True)
        else:
            self.termVis = False
            self.termAct.setChecked(False)

    def toggleIntGuide(self):
        state = self.edit.indentationGuides()
        self.edit.setIndentationGuides(not state)

    def toggleLN(self):
        state = self.edit.marginLineNumbers(0)
        self.edit.setMarginLineNumbers(0, not state)
        self.edit.setMarginWidth(0,0) if state == True else self.edit. \
                                setMarginWidth(0,self.edit.metrics.width("00000"))

    def fr(self):
        frwin = Find(self)
        frwin.show()

    def chooseFont(self):
        font, ok = QFontDialog.getFont()
        if ok:
            config.font = font
            try:
                self.getEditor(self.tab.currentIndex()).lexer().setFont(
                    config.font)
            except AttributeError:
                self.getEditor(self.tab.currentIndex()).setLang(
                    QsciLexerText())
                #print self.getEditor(self.tab.currentIndex()).lexer()
                self.getEditor(self.tab.currentIndex()).lexer().setFont(
                    config.font)

    def setProDir(self):
        pdir, ok = QInputDialog.getText(self, "Set Project Directory",
                                             "Enter absolute path (i.e. "\
                                             "/home/steve/Documents)")
        if ok:
            config.proDir = pdir
            #print config.proDir

    # This method adapted from Peter Goldsborough's Writer.
    # Save settings and alerts the user if they are saving an edited file.
    def closeEvent(self, event):
        self.writeSettings()
        self.saveDocs()
        if not self.edit.isModified():
            event.accept()
        else:
            dialog = QMessageBox(self)
            dialog.setIcon(QMessageBox.Warning)
            dialog.setText(config.filename + " has unsaved changes.")
            dialog.setInformativeText("Do you want to save your changes?")
            dialog.setStandardButtons(QMessageBox.Save | QMessageBox.Cancel
                                      | QMessageBox.Discard)
            dialog.setDefaultButton(QMessageBox.Save)
            response = dialog.exec_()
            if response == QMessageBox.Save:
                self.save()
            elif response == QMessageBox.Discard:
                event.accept()
            else:
                event.ignore()

    def resizeEvent(self, event):
        # Don't try to resize a non-existant file tree
        try:
            self.ftree.treeView.resize(self.ftree.treeView.width(),
                                       self.height())
        except:
            pass
        try:
            self.term.resize(self.width(), self.term.height())
        except:
            pass

    def keyPressEvent(self, event):
        key = event.key()
        if (self.getEditor(self.tab.currentIndex()).text() == "bee movie"):
            with open("bee_movie.txt", "r") as file:
                script = file.read()
            self.getEditor(self.tab.currentIndex()).setText(script)