diff options
author | Blaine | 2020-04-26 22:05:13 +0530 |
---|---|---|
committer | Blaine | 2020-04-26 22:05:13 +0530 |
commit | e3cdc7d698a3f400f600e13fa9e647a1d909aff2 (patch) | |
tree | ae5c756280cdfede808b64cc48bc221adabefcfe /src | |
parent | 0477ce548a303c20c33eb7abc8fe6166f18c3359 (diff) | |
download | Chemical-PFD-e3cdc7d698a3f400f600e13fa9e647a1d909aff2.tar.gz Chemical-PFD-e3cdc7d698a3f400f600e13fa9e647a1d909aff2.tar.bz2 Chemical-PFD-e3cdc7d698a3f400f600e13fa9e647a1d909aff2.zip |
comments and minor cleanup
Diffstat (limited to 'src')
-rw-r--r-- | src/main/python/main.py | 36 | ||||
-rw-r--r-- | src/main/python/utils/canvas.py | 114 | ||||
-rw-r--r-- | src/main/python/utils/dialogs.py | 32 | ||||
-rw-r--r-- | src/main/python/utils/tabs.py | 26 |
4 files changed, 133 insertions, 75 deletions
diff --git a/src/main/python/main.py b/src/main/python/main.py index 953c6c8..5afb350 100644 --- a/src/main/python/main.py +++ b/src/main/python/main.py @@ -15,39 +15,46 @@ from utils import dialogs class appWindow(QMainWindow): + """ + Application entry point, subclasses QMainWindow and implements the main widget, + sets necessary window behaviour etc. + """ def __init__(self, parent=None): super(appWindow, self).__init__(parent) + self.mainWidget = QWidget(self) #create new widget - titleMenu = self.menuBar() - self.mainWidget = QWidget(self) + #create the menu bar + titleMenu = self.menuBar() #fetch reference to current menu bar self.mainWidget.setObjectName("Main Widget") self.menuFile = titleMenu.addMenu('File') #File Menu self.menuFile.addAction("New", self.newProject) self.menuFile.addAction("Open", self.openProject) self.menuFile.addAction("Save", self.saveProject) + self.menuGenerate = titleMenu.addMenu('Generate') #Generate menu self.menuGenerate.addAction("Image", self.saveImage) self.menuGenerate.addAction("Report", self.generateReport) - # mainLayout = QGridLayout(self.mainWidget) + # create new layout for the main widget mainLayout = QHBoxLayout(self.mainWidget) mainLayout.setObjectName("Main Layout") - #ImpsaveProject - self.mdi = QMdiArea(self) - # add close action to tabs + self.mdi = QMdiArea(self) #create area for files to be displayed + #create toolbar and add the toolbar plus mdi to layout self.createToolbar() mainLayout.addWidget(self.toolbar) mainLayout.addWidget(self.mdi) + #declare main window layout self.mainWidget.setLayout(mainLayout) self.setCentralWidget(self.mainWidget) - self.resize(1280, 720) - self.setWindowState(Qt.WindowMaximized) + self.resize(1280, 720) #set collapse dim + self.setWindowState(Qt.WindowMaximized) #launch maximized def createToolbar(self): + #place holder for toolbar with fixed width, layout may change self.toolbar = QWidget(self.mainWidget) self.toolbar.setObjectName("Toolbar") self.toolbar.setFixedWidth(200) @@ -55,15 +62,17 @@ class appWindow(QMainWindow): self.toolbar.setLayout(toolbarLayout) def newProject(self): + #call to create a new file inside mdi area project = fileWindow(self.mdi) project.setObjectName("New Project") self.mdi.addSubWindow(project) - if not project.tabList: - project.newDiagram() + if not project.tabList: # important when unpickling a file instead + project.newDiagram() #create a new tab in the new file project.show() project.resizeHandler(self.mdi) def openProject(self): + #show the open file dialog to open a saved file, then unpickle it. name = QFileDialog.getOpenFileNames(self, 'Open File(s)', '', 'Process Flow Diagram (*pfd)') if name: for files in name[0]: @@ -74,7 +83,8 @@ class appWindow(QMainWindow): project.resizeHandler(self.mdi) def saveProject(self): - for j, i in enumerate(self.mdi.subWindowList()): + #pickle all files in mdi area + for j, i in enumerate(self.mdi.activeFiles): #get list of all windows with atleast one tab if i.tabCount: name = QFileDialog.getSaveFileName(self, 'Save File', f'New Diagram {j}', 'Process Flow Diagram (*.pfd)') i.saveProject(name) @@ -83,17 +93,21 @@ class appWindow(QMainWindow): return True def saveImage(self): + #place holder for future implementaion pass def generateReport(self): + #place holder for future implementaion pass def resizeEvent(self, event): + #overload resize to also handle resize on file windows inside if self.mdi.activeSubWindow(): self.mdi.activeSubWindow().resizeHandler(self.mdi) super(appWindow, self).resizeEvent(event) def closeEvent(self, event): + #save alert on window close if len(self.activeFiles) and dialogs.saveEvent(self): event.accept() else: diff --git a/src/main/python/utils/canvas.py b/src/main/python/utils/canvas.py index 330d3be..dac1d98 100644 --- a/src/main/python/utils/canvas.py +++ b/src/main/python/utils/canvas.py @@ -12,32 +12,48 @@ from .sizes import paperSizes, ppiList, sheetDimensionList from .tabs import customTabWidget class canvas(QWidget): + """ + Defines the work area for a single sheet. Contains a QGraphicScene along with necessary properties + for context menu and dialogs. + """ + def __init__(self, parent=None, size= 'A4', ppi= '72'): super(canvas, self).__init__(parent) + #Store values for the canvas dimensions for ease of access, these are here just to be + # manipulated by the setters and getters self._ppi = ppi self._canvasSize = size + #Create area for the graphic items to be placed, this is just here right now for the future + # when we will draw items on this, this might be changed if QGraphicScene is subclassed. self.painter = QGraphicsScene() self.painter.setSceneRect(0, 0, *paperSizes[self.canvasSize][self.ppi]) - self.painter.setBackgroundBrush(QBrush(Qt.white)) + self.painter.setBackgroundBrush(QBrush(Qt.white)) #set white background - self.view = QGraphicsView(self.painter) - self.view.setMinimumSize(595, 842) - self.view.setSceneRect(0, 0, *paperSizes[self.canvasSize][self.ppi]) + self.view = QGraphicsView(self.painter) #create a viewport for the canvas board + self.view.setMinimumSize(595, 842) #experimentation for the viewport overflow + self.view.setSceneRect(0, 0, *paperSizes[self.canvasSize][self.ppi]) # use the dimensions set previously - self.layout = QHBoxLayout(self) + self.layout = QHBoxLayout(self) #create the layout of the canvas, the canvas could just subclass QGView instead self.layout.addWidget(self.view) self.setLayout(self.layout) + #This is done so that a right click menu is shown on right click self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.contextMenu) def setCanvasSize(self, size): + """ + extended setter for dialog box + """ self.canvasSize = size - def setCanvasPPI(self, ppi): + def setCanvasPPI(self, ppi): + """ + extended setter for dialog box + """ self.ppi = ppi @property @@ -63,16 +79,21 @@ class canvas(QWidget): @property def dimensions(self): + #returns the dimension of the current scene return self.painter.sceneRect().width(), self.painter.sceneRect().height() def contextMenu(self, point): + #function to display the right click menu at point of right click menu = QMenu("Context Menu", self) menu.addAction("Adjust Canvas", self.adjustCanvasDialog) menu.exec_(self.mapToGlobal(point)) def adjustCanvasDialog(self): + #helper function to the context menu dialog box self.canvasSize, self.ppi = dialogs.paperDims(self, self._canvasSize, self._ppi, self.objectName).exec_() + #following 2 methods are defined for correct pickling of the scene. may be changed to json or xml later so as + # to not have a binary file. def __getstate__(self) -> dict: return { "_classname_": self.__class__.__name__, @@ -93,54 +114,43 @@ class canvas(QWidget): self.painter.addItem(graphic) class fileWindow(QMdiSubWindow): + """ + This defines a single file, inside the application, consisting of multiple tabs that contain + canvases. Pre-Defined so that a file can be instantly created without defining the structure again. + """ def __init__(self, parent = None, title = 'New Project', size = 'A4', ppi = '72'): super(fileWindow, self).__init__(parent) + #Uses a custom QTabWidget that houses a custom new Tab Button, used to house the seperate + # diagrams inside a file self.tabber = customTabWidget(self) - self.tabber.setObjectName(title) - self.tabber.tabCloseRequested.connect(self.closeTab) - self.tabber.currentChanged.connect(self.changeTab) - self.tabber.plusClicked.connect(self.newDiagram) + self.tabber.setObjectName(title) #store title as object name for pickling + self.tabber.tabCloseRequested.connect(self.closeTab) # Show save alert on tab close + self.tabber.currentChanged.connect(self.changeTab) # placeholder just to detect tab change + self.tabber.plusClicked.connect(self.newDiagram) #connect the new tab button to add a new tab + #assign layout to widget self.setWidget(self.tabber) - self.setWindowTitle(title) - - @property - def canvasSize(self): - return self._canvasSize - @property - def ppi(self): - return self._ppi - - @canvasSize.setter - def canvasSize(self, size): - self._canvasSize = sheetDimensionList.index(size) - if self.tabCount: - activeTab = self.tabber.currentWidget() - activeTab.canvasSize = size - - @ppi.setter - def ppi(self, ppi): - self._ppi = ppiList.index(ppi) - if self.tabCount: - activeTab = self.tabber.currentWidget() - activeTab.ppi = ppi - + self.setWindowTitle(title) def changeTab(self, currentIndex): + #placeholder function to detect tab change pass def closeTab(self, currentIndex): + #show save alert on tab close if dialogs.saveEvent(self): self.tabber.widget(currentIndex).deleteLater() self.tabber.removeTab(currentIndex) def newDiagram(self): + # helper function to add a new tab on pressing new tab button, using the add tab method on QTabWidget diagram = canvas(self.tabber) diagram.setObjectName("New") self.tabber.addTab(diagram, "New") def resizeHandler(self, parent = None): + # experimental resize Handler to handle resize on parent resize. parentRect = parent.rect() if parent else self.parent().rect() self.resize(parentRect.width(), parentRect.height()) self.setMaximumHeight(parentRect.height()) @@ -150,12 +160,34 @@ class fileWindow(QMdiSubWindow): @property def tabList(self): + #returns a list of tabs in the given window return [self.tabber.widget(i) for i in range(self.tabCount)] @property def tabCount(self): + #returns the number of tabs in the given window only return self.tabber.count() + def saveProject(self, name = None): + # called by dialog.saveEvent, saves the current file + name = QFileDialog.getSaveFileName(self, 'Save File', f'New Diagram', 'Process Flow Diagram (*.pfd)') if not name else name + if name: + with open(name[0],'wb') as file: + pickle.dump(self, file) + return True + else: + return False + + def closeEvent(self, event): + # handle save alert on file close, check if current file has no tabs aswell. + if self.tabCount==0 or dialogs.saveEvent(self): + event.accept() + self.deleteLater() + else: + event.ignore() + + #following 2 methods are defined for correct pickling of the scene. may be changed to json or xml later so as + # to not have a binary file. def __getstate__(self) -> dict: return { "_classname_": self.__class__.__name__, @@ -172,18 +204,4 @@ class fileWindow(QMdiSubWindow): diagram.__setstate__(i) self.tabber.addTab(diagram, i['ObjectName']) - def saveProject(self, name = None): - name = QFileDialog.getSaveFileName(self, 'Save File', f'New Diagram', 'Process Flow Diagram (*.pfd)') if not name else name - if name: - with open(name[0],'wb') as file: - pickle.dump(self, file) - return True - else: - return False - - def closeEvent(self, event): - if self.tabCount==0 or dialogs.saveEvent(self): - event.accept() - self.deleteLater() - else: - event.ignore() +
\ No newline at end of file diff --git a/src/main/python/utils/dialogs.py b/src/main/python/utils/dialogs.py index d2b872c..38d68d9 100644 --- a/src/main/python/utils/dialogs.py +++ b/src/main/python/utils/dialogs.py @@ -2,52 +2,66 @@ from PyQt5.QtWidgets import QDialog, QPushButton, QFormLayout, QComboBox, QLabel from .sizes import sheetDimensionList, ppiList class paperDims(QDialog): + """ + Utility dialog box to adjust the current canvas's dimensions, might return just dimensions later + so that sizes do not need to be imported in every other module. + """ def __init__(self, parent=None, size='A4', ppi='72', name='Canvas Size'): super(paperDims, self).__init__(parent) + #store initial values to show currently set value, also updated when changed. these are returned at EOL self._canvasSize = size self._ppi = ppi - self.setWindowTitle(name+":Canvas Size") + self.setWindowTitle(name+":Canvas Size") #Set Window Title + #init layout dialogBoxLayout = QFormLayout(self) - sizeComboBox = QComboBox() + + sizeComboBox = QComboBox() #combo box for paper sizes sizeComboBox.addItems(sheetDimensionList) sizeComboBox.setCurrentIndex(4) sizeComboBox.activated[str].connect(self.setCanvasSize) sizeLabel = QLabel("Canvas Size") - sizeLabel.setBuddy(sizeComboBox) - sizeComboBox.setCurrentIndex(sheetDimensionList.index(self._canvasSize)) + sizeLabel.setBuddy(sizeComboBox) # label for the above combo box + sizeComboBox.setCurrentIndex(sheetDimensionList.index(self._canvasSize)) #set index to current value of canvas dialogBoxLayout.setWidget(0, QFormLayout.LabelRole, sizeLabel) dialogBoxLayout.setWidget(0, QFormLayout.FieldRole, sizeComboBox) - ppiComboBox = QComboBox() + ppiComboBox = QComboBox() #combo box for ppis ppiComboBox.addItems(ppiList) ppiComboBox.activated[str].connect(self.setCanvasPPI) ppiLabel = QLabel("Canvas ppi") - ppiLabel.setBuddy(ppiComboBox) - ppiComboBox.setCurrentIndex(ppiList.index(self._ppi)) + ppiLabel.setBuddy(ppiComboBox) # label for the above combo box + ppiComboBox.setCurrentIndex(ppiList.index(self._ppi)) #set index to current value of canvas dialogBoxLayout.setWidget(1, QFormLayout.LabelRole, ppiLabel) dialogBoxLayout.setWidget(1, QFormLayout.FieldRole, ppiComboBox) self.setLayout(dialogBoxLayout) - self.resize(400,300) + self.resize(400,300) #resize to a certain size + + #todo add ok or cancel buttons def setCanvasSize(self, size): + #for standard combo box behaviour self._canvasSize = size def setCanvasPPI(self, ppi): + #for standard combo box behaviour self._ppi = ppi def exec_(self): + #overload exec_ to add return values and delete itself(currently being tested) super(paperDims, self).exec_() + self.deleteLater() return self._canvasSize, self._ppi def saveEvent(parent = None): + #utility function to generate a Qt alert window requesting the user to save the file, returns user intention on window close alert = QMessageBox.question(parent, parent.objectName(), "All unsaved progress will be LOST!", QMessageBox.StandardButtons(QMessageBox.Save|QMessageBox.Ignore|QMessageBox.Cancel), QMessageBox.Save) if alert == QMessageBox.Cancel: return False else: if alert == QMessageBox.Save: - if not parent.saveProject(): + if not parent.saveProject(): #the parent's saveProject method is called which returns false if saving was cancelled by the user return False return True
\ No newline at end of file diff --git a/src/main/python/utils/tabs.py b/src/main/python/utils/tabs.py index 3dfb641..7d8bb1d 100644 --- a/src/main/python/utils/tabs.py +++ b/src/main/python/utils/tabs.py @@ -2,6 +2,9 @@ from PyQt5.QtWidgets import QTabBar, QPushButton, QTabWidget from PyQt5.QtCore import pyqtSignal, QSize class tabBarPlus(QTabBar): + """ + Just implemented to overload resize and layout change to emit a signal + """ layoutChanged = pyqtSignal() def resizeEvent(self, event): super().resizeEvent(event) @@ -13,26 +16,35 @@ class tabBarPlus(QTabBar): class customTabWidget(QTabWidget): + """ + QTabWidget with a new tab button, also catches layoutChange signal by + the tabBarPlus to dynamically move the button to the correct location + """ plusClicked = pyqtSignal() def __init__(self, parent=None): super(customTabWidget, self).__init__(parent) self.tab = tabBarPlus() - self.setTabBar(self.tab) + self.setTabBar(self.tab) #set tabBar to our custom tabBarPlus - self.plusButton = QPushButton('+', self) - self.plusButton.setFixedSize(35, 25) - self.plusButton.clicked.connect(self.plusClicked.emit) + self.plusButton = QPushButton('+', self) #create the new tab button + #and parent it to the widget to add it at 0, 0 + self.plusButton.setFixedSize(35, 25) #set dimensions + self.plusButton.clicked.connect(self.plusClicked.emit) #emit signal on click + #set flags self.setMovable(True) self.setTabsClosable(True) - self.tab.layoutChanged.connect(self.movePlusButton) + self.tab.layoutChanged.connect(self.movePlusButton) #connect layout change + # to dynamically move the button. def movePlusButton(self): + #move the new tab button to correct location size = sum([self.tab.tabRect(i).width() for i in range(self.tab.count())]) - h = max(self.tab.geometry().bottom() - 25, 0) + # calculate width of all tabs + h = max(self.tab.geometry().bottom() - 25, 0) #align with bottom of tabbar w = self.tab.width() - if size > w: + if size > w: #if all the tabs do not overflow the tab bar, add at the end self.plusButton.move(w-self.plusButton.width(), h) else: self.plusButton.move(size-3, h)
\ No newline at end of file |