#!/usr/bin/env python
from PySide import QtCore
from PySide import QtGui
import sys
import os.path
import ConfigParser
import logging
from editor import TextEditor
homeDir=os.path.expanduser("~")
""" Main IDE window class
Initializes the main window and the editor
"""
class MainCodeWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainCodeWindow, self).__init__(parent)
self.setWindowTitle("Codebug [*]")
self.setWindowIcon(QtGui.QIcon(u'pycodebug.png'))
self.setMinimumSize(QtCore.QSize(800,600))
self.editor=TextEditor()
self.editor.setLineWrapMode(QtGui.QTextEdit.NoWrap)
self.recentViewList=None
self.setCentralWidget(self.editor)
self.curPath=""
self.loadConfig()
self.initMenu()
self.loadLastFile()
self.editor.setStatusBar(self.statusBar())
self.editor.setMainWindow(self)
self.editor.document().contentsChanged.connect(self.textChanged)
def openPanes(self):
if self.config.has_section('panes'):
if self.config.get('panes','recent')=='True':
self.viewRecent()
def loadConfig(self):
try:
self.recent=[]
cfgpath=os.path.join(homeDir, "pycodebug.ini")
self.config = ConfigParser.RawConfigParser(allow_no_value=True)
self.config.readfp(open(cfgpath))
for i in xrange(1,9):
f='file{}'.format(i)
if self.config.has_option('recent',f):
self.recent.append(self.config.get('recent',f))
except IOError:
pass
def saveConfig(self):
try:
cfgpath=os.path.join(homeDir, "pycodebug.ini")
self.config.write(open(cfgpath,'w'))
except IOError:
pass
def textChanged(self):
self.setWindowModified(True)
def closeEvent(self, event):
""" Check if code is modified before closing """
self.saveConfig()
self.editor.closeCallouts()
if self.maybeSave():
event.accept()
else:
event.ignore()
def maybeSave(self):
""" Ask the user whether to save the file """
if self.editor.document().isModified():
ret = QtGui.QMessageBox.warning(self, "Codebug",
"The source has been modified.\n"
"Do you want to save your changes?",
QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard |
QtGui.QMessageBox.Cancel)
if ret == QtGui.QMessageBox.Save:
return self.save()
elif ret == QtGui.QMessageBox.Cancel:
return False
return True
def moveEvent(self, event):
""" Window moved. Move annotation callouts """
d=event.pos()
d-=event.oldPos()
self.editor.moveCallouts(d)
def addMenuAction(self,menu,icon,text,short,tip,slot):
action=QtGui.QAction(QtGui.QIcon(icon),text,self)
if len(short)>0:
action.setShortcut(short)
if len(tip)>0:
action.setStatusTip(tip)
action.triggered.connect(slot)
menu.addAction(action)
def initMenu(self):
""" Create the main window menus """
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
self.addMenuAction(fileMenu,'new.png','&New','Ctrl+N','New File',self.newFile)
self.addMenuAction(fileMenu,'open.png','&Open','Ctrl+O','Open File',self.open)
self.addMenuAction(fileMenu,'save.png','&Save','Ctrl+S','Save File',self.save)
self.addMenuAction(fileMenu,'saveas.png','&Save As','','Save As File',self.saveAs)
self.recentMenu = fileMenu.addMenu('&Recent Files')
self.updateRecent()
self.addMenuAction(fileMenu,'exit.png','&Exit','Ctrl+Q','Exit Application',self.close)
viewMenu = menubar.addMenu('&View')
self.addMenuAction(viewMenu,'reclist.png','&Recent','','Recent Files',self.viewRecent)
def updateRecent(self):
# Update the recent files list pane
if not self.recentViewList is None:
self.recentViewList.clear()
for f in self.recent:
self.recentViewList.addItem(f)
# Update the menu items
self.recentMenu.clear()
for f in self.recent:
item=QtGui.QAction(QtGui.QIcon('none.png'),f,self)
item.triggered.connect(lambda : self.load(f))
self.recentMenu.addAction(item)
# Update recent files in the config
if not self.config.has_section('recent'):
self.config.add_section('recent')
for i in xrange(1,9):
self.config.remove_option('recent','file{}'.format(i))
for idx,f in enumerate(self.recent):
name='file{}'.format(idx+1)
self.config.set('recent',name,f)
def setFileTitle(self):
""" Set the main window title (filename) """
self.setWindowTitle("{}[*] - Codebug".format(self.curPath))
def setCurPath(self, p):
self.curPath=p
self.tmpPath=os.path.join(os.path.dirname(p), "pycodebug_tmp.py")
self.editor.setTmpPath(self.tmpPath)
def viewRecent(self):
self.paneRecent=QtGui.QDockWidget("Recent Files",self)
self.paneRecent.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea)
self.recentViewList=QtGui.QListWidget(self.paneRecent)
for f in self.recent:
self.recentViewList.addItem(f)
self.recentViewList.itemClicked.connect(lambda item: self.load(item.text()))
self.paneRecent.setWidget(self.recentViewList)
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea,self.paneRecent)
self.paneRecent.visibilityChanged.connect(lambda x: self.dockPaneVisibility("recent",x))
def dockPaneVisibility(self,pane,state):
if not self.config.has_section('panes'):
self.config.add_section('panes')
self.config.set('panes',pane,str(state))
""" Load a python source file to the editor """
def load(self, filepath):
if self.maybeSave():
try:
contents=open(filepath).read()
self.editor.setText(contents)
self.editor.document().setModified(False)
self.setCurPath(filepath)
self.setFileTitle()
if filepath in self.recent:
self.recent.remove(filepath)
self.recent.insert(0,filepath)
if len(self.recent)>9:
self.recent=self.recent[0:9]
self.updateRecent()
return True
except IOError:
return False
""" Open menu item.
Choose a file using a file dialog
"""
def open(self):
filepath, filefilter=QtGui.QFileDialog.getOpenFileName(filter="Python file (*.py)")
if len(filepath)>0:
self.load(filepath)
def newFile(self):
filepath, filefilter=QtGui.QFileDialog.getSaveFileName(filter="Python file (*.py)")
if len(filepath)==0:
return False
self.editor.setText("")
self.setCurPath(filepath)
self.setFileTitle()
return self.save()
""" Save As
Ask for a new filename to save
"""
def saveAs(self):
filepath, filefilter=QtGui.QFileDialog.getSaveFileName(filter="Python file (*.py)")
if len(filepath)==0:
return False
self.setCurPath(filepath)
self.setFileTitle()
return self.save()
""" Save the file with the current filename """
def save(self):
if len(self.curPath)>0:
try:
open(self.curPath, "w").write(self.editor.toPlainText())
self.editor.document().setModified(False)
self.setWindowModified(False)
return True
except IOError:
return False
else:
return self.saveAs()
def close(self):
self.saveConfig()
super(MainCodeWindow,self).close()
""" Get the last file edited from the user home directory and load it """
def loadLastFile(self):
try:
if len(self.recent)>0:
lastFile=self.recent[0]
self.load(lastFile)
except IOError:
pass
""" Main function. Start the GUI """
def main():
app=QtGui.QApplication(sys.argv)
#logging.basicConfig(filename='codebug.log',level=logging.DEBUG)
w=MainCodeWindow()
if len(sys.argv)>1:
w.load(sys.argv[1])
w.show()
w.openPanes()
app.exec_()
if __name__ == '__main__':
main()