diff options
author | pravindalve | 2020-06-10 17:22:06 +0530 |
---|---|---|
committer | GitHub | 2020-06-10 17:22:06 +0530 |
commit | fd3ff2c037805a6539a9044bd9d26c3400768be8 (patch) | |
tree | e39adff23664647035bdf9c12357b820ed204065 /src/main/python | |
parent | 0d33ceda3262494437fe022466e4368db62c8849 (diff) | |
parent | 48549adea85f9dd08da71b4e4dd310858a391e22 (diff) | |
download | Chemical-PFD-fd3ff2c037805a6539a9044bd9d26c3400768be8.tar.gz Chemical-PFD-fd3ff2c037805a6539a9044bd9d26c3400768be8.tar.bz2 Chemical-PFD-fd3ff2c037805a6539a9044bd9d26c3400768be8.zip |
Merge pull request #12 from Blakeinstein/master
Implement saving + implement svg files
Diffstat (limited to 'src/main/python')
-rw-r--r-- | src/main/python/shapes/__init__.py | 2 | ||||
-rw-r--r-- | src/main/python/shapes/line.py | 22 | ||||
-rw-r--r-- | src/main/python/shapes/shapes.py | 305 | ||||
-rw-r--r-- | src/main/python/utils/app.py | 6 | ||||
-rw-r--r-- | src/main/python/utils/canvas.py | 42 | ||||
-rw-r--r-- | src/main/python/utils/fileWindow.py | 11 | ||||
-rw-r--r-- | src/main/python/utils/tabs.py | 23 | ||||
-rw-r--r-- | src/main/python/utils/toolbar.py | 21 | ||||
-rw-r--r-- | src/main/python/utils/undo.py | 3 |
9 files changed, 115 insertions, 320 deletions
diff --git a/src/main/python/shapes/__init__.py b/src/main/python/shapes/__init__.py index af92a6a..536caf6 100644 --- a/src/main/python/shapes/__init__.py +++ b/src/main/python/shapes/__init__.py @@ -1,4 +1,4 @@ from .shapes import * -# from .line import * +from .line import LineLabel from PyQt5.QtWidgets import * dir()
\ No newline at end of file diff --git a/src/main/python/shapes/line.py b/src/main/python/shapes/line.py index 92c5b1d..466e22b 100644 --- a/src/main/python/shapes/line.py +++ b/src/main/python/shapes/line.py @@ -259,6 +259,19 @@ class LineLabel(QGraphicsTextItem): def focusOutEvent(self, event): super(LineLabel, self).focusOutEvent(event) self.setTextInteractionFlags(Qt.NoTextInteraction) + + def __getstate__(self): + return { + "text": self.toPlainText(), + "index": self.index, + "gap": self.gap, + "pos": (self.pos().x(), self.pos().y()) + } + + def __setstate__(self, dict): + self.setPlainText(dict['text']) + self.index = dict['index'] + self.gap = dict['gap'] def findIndex(line, pos): @@ -919,8 +932,13 @@ class Line(QGraphicsPathItem): "_classname_": self.__class__.__name__, "startPoint": (self.startPoint.x(), self.startPoint.y()), "endPoint": (self.endPoint.x(), self.endPoint.y()), - "points": [(point.x(), point.y()) for point in self.points] + "points": [(point.x(), point.y()) for point in self.points], + "startGripItem": hex(id(self.startGripItem)), + "endGripItem": hex(id(self.endGripItem)) if self.endGripItem else 0, + "refLine": hex(id(self.refLine)) if self.refLine else 0, + "refIndex": self.refIndex, + "label": [i for i in self.label], + "id": hex(id(self)) } - def __setstate__(self, dict): self.points = [QPointF(x, y) for x, y in dict["points"]] diff --git a/src/main/python/shapes/shapes.py b/src/main/python/shapes/shapes.py index 0358898..b825653 100644 --- a/src/main/python/shapes/shapes.py +++ b/src/main/python/shapes/shapes.py @@ -12,7 +12,6 @@ from PyQt5.QtWidgets import (QGraphicsColorizeEffect, QGraphicsEllipseItem, from .line import Line, findIndex from utils.app import fileImporter -from utils.app import fileImporter class ItemLabel(QGraphicsTextItem): def __init__(self, pos, parent=None): @@ -33,7 +32,16 @@ class ItemLabel(QGraphicsTextItem): def focusOutEvent(self, event): super(ItemLabel, self).focusOutEvent(event) self.setTextInteractionFlags(Qt.NoTextInteraction) + + def __getstate__(self): + return { + "text": self.toPlainText(), + "pos": (self.pos().x(), self.pos().y()) + } + def __setstate__(self, dict): + self.setPlainText(dict['text']) + self.setPos(*dict['pos']) class GripItem(QGraphicsPathItem): """ @@ -318,16 +326,13 @@ class NodeItem(QGraphicsSvgItem): Extends PyQt5's QGraphicsSvgItem to create the basic structure of shapes with given unit operation type """ # set a common renderer for all svg - renderer = QSvgRenderer(fileImporter(f'svg/ellipse.svg')) + # renderer = QSvgRenderer(fileImporter(f'svg/ellipse.svg')) def __init__(self, unitOperationType=None, parent=None): QGraphicsSvgItem.__init__(self, parent) self.m_type = str(unitOperationType) self.id = None - # self.m_renderer = QSvgRenderer("svg/" + unitOperationType + ".svg") - # self.m_renderer = QSvgRenderer(fileImporter(f'svg/{unitOperationType}.svg')) - self.m_renderer = QSvgRenderer(fileImporter(f'svg/ellipse.svg')) - # self.m_renderer = QSvgRenderer(resourceManager.get_resource(f'toolbar/{unitOperationType}.svg')) + self.m_renderer = QSvgRenderer(fileImporter(f'{unitOperationType}.svg')) self.setSharedRenderer(self.m_renderer) # set initial size of item self.width = 100 @@ -498,7 +503,9 @@ class NodeItem(QGraphicsSvgItem): "_classname_": self.__class__.__name__, "width": self.width, "height": self.height, - "pos": (self.pos().x(), self.pos().y()) + "pos": (self.pos().x(), self.pos().y()), + "lineGripItems": [(hex(id(i)), i.m_index) for i in self.lineGripItems], + "label": self.label } def __setstate__(self, dict): @@ -506,287 +513,5 @@ class NodeItem(QGraphicsSvgItem): self.width = dict['width'] self.height = dict['height'] self.rect = QRectF(-self.width / 2, -self.height / 2, self.width, self.height) - transform = QTransform() - transform.translate(self.width / 2, self.height / 2) - self.setTransform(transform, True) self.updateSizeGripItem() - -# classes of pfd-symbols -class AirBlownCooler(NodeItem): - def __init__(self): - super(AirBlownCooler, self).__init__("AirBlownCooler", parent=None) - - -class Bag(NodeItem): - def __init__(self): - super(Bag, self).__init__("Bag", parent=None) - - -class Boiler(NodeItem): - def __init__(self): - super(Boiler, self).__init__("Boiler", parent=None) - - -class Breaker(NodeItem): - def __init__(self): - super(Breaker, self).__init__("Breaker", parent=None) - - -class BriquettingMachine(NodeItem): - def __init__(self): - super(BriquettingMachine, self).__init__("BriquettingMachine", parent=None) - - -class Centrifugal(NodeItem): - def __init__(self): - super(Centrifugal, self).__init__("Centrifugal", parent=None) - - -class CentrifugalCompressor(NodeItem): - def __init__(self): - super(CentrifugalCompressor, self).__init__("CentrifugalCompressor", parent=None) - - -class Centrifugalpump(NodeItem): - def __init__(self): - super(Centrifugalpump, self).__init__("Centrifugalpump", parent=None) - - -class CentrifugalPump2(NodeItem): - def __init__(self): - super(CentrifugalPump2, self).__init__("CentrifugalPump2", parent=None) - - -class CentrifugalPump3(NodeItem): - def __init__(self): - super(CentrifugalPump3, self).__init__("CentrifugalPump3", parent=None) - - -class Column(NodeItem): - def __init__(self): - super(Column, self).__init__("Column", parent=None) - - -class Compressor(NodeItem): - def __init__(self): - super(Compressor, self).__init__("Compressor", parent=None) - - -class CompressorSilencers(NodeItem): - def __init__(self): - super(CompressorSilencers, self).__init__("CompressorSilencers", parent=None) - - -class Condenser(NodeItem): - def __init__(self): - super(Condenser, self).__init__("Condenser", parent=None) - - -class Cooler(NodeItem): - def __init__(self): - super(Cooler, self).__init__("Cooler", parent=None) - - -class CoolingTower3(NodeItem): - def __init__(self): - super(CoolingTower3, self).__init__("CoolingTower3", parent=None) - - -class CoolingTwoer2(NodeItem): - def __init__(self): - super(CoolingTwoer2, self).__init__("CoolingTwoer2", parent=None) - - -class Crusher(NodeItem): - def __init__(self): - super(Crusher, self).__init__("Crusher", parent=None) - - -class DoublePipeHeat(NodeItem): - def __init__(self): - super(DoublePipeHeat, self).__init__("DoublePipeHeat", parent=None) - - -class ExtractorHood(NodeItem): - def __init__(self): - super(ExtractorHood, self).__init__("ExtractorHood", parent=None) - - -class FiredHeater(NodeItem): - def __init__(self): - super(FiredHeater, self).__init__("FiredHeater", parent=None) - - -class ForcedDraftCooling(NodeItem): - def __init__(self): - super(ForcedDraftCooling, self).__init__("ForcedDraftCooling", parent=None) - - -class Furnace(NodeItem): - def __init__(self): - super(Furnace, self).__init__("Furnace", parent=None) - - -class GasBottle(NodeItem): - def __init__(self): - super(GasBottle, self).__init__("GasBottle", parent=None) - - -class HalfPipeMixingVessel(NodeItem): - def __init__(self): - super(HalfPipeMixingVessel, self).__init__("HalfPipeMixingVessel", parent=None) - - -class Heater(NodeItem): - def __init__(self): - super(Heater, self).__init__("Heater", parent=None) - - -class HeatExchanger(NodeItem): - def __init__(self): - super(HeatExchanger, self).__init__("HeatExchanger", parent=None) - - -class HeatExchanger2(NodeItem): - def __init__(self): - super(HeatExchanger2, self).__init__("HeatExchanger2", parent=None) - - -class HorizontalVessel(NodeItem): - def __init__(self): - super(HorizontalVessel, self).__init__("HorizontalVessel", parent=None) - - -class InducedDraftCooling(NodeItem): - def __init__(self): - super(InducedDraftCooling, self).__init__("InducedDraftCooling", parent=None) - - -class JacketedMixingVessel(NodeItem): - def __init__(self): - super(JacketedMixingVessel, self).__init__("JacketedMixingVessel", parent=None) - - -class LiquidRingCompressor(NodeItem): - def __init__(self): - super(LiquidRingCompressor, self).__init__("LiquidRingCompressor", parent=None) - - -class Mixing(NodeItem): - def __init__(self): - super(Mixing, self).__init__("Mixing", parent=None) - - -class MixingReactor(NodeItem): - def __init__(self): - super(MixingReactor, self).__init__("MixingReactor", parent=None) - - -class OilBurner(NodeItem): - def __init__(self): - super(OilBurner, self).__init__("OilBurner", parent=None) - - -class OpenTank(NodeItem): - def __init__(self): - super(OpenTank, self).__init__("OpenTank", parent=None) - - -class ProportionalPump(NodeItem): - def __init__(self): - super(ProportionalPump, self).__init__("ProportionalPump", parent=None) - - -class Pump(NodeItem): - def __init__(self): - super(Pump, self).__init__("Pump", parent=None) - - -class Pump2(NodeItem): - def __init__(self): - super(Pump2, self).__init__("Pump2", parent=None) - - -class ReboilerHeatExchange(NodeItem): - def __init__(self): - super(ReboilerHeatExchange, self).__init__("ReboilerHeatExchange", parent=None) - - -class ReciprocatingCompressor(NodeItem): - def __init__(self): - super(ReciprocatingCompressor, self).__init__("ReciprocatingCompressor", parent=None) - - -class RotaryCompresor(NodeItem): - def __init__(self): - super(RotaryCompresor, self).__init__("RotaryCompresor", parent=None) - - -class RotaryGearPump(NodeItem): - def __init__(self): - super(RotaryGearPump, self).__init__("RotaryGearPump", parent=None) - - -class ScrewPump(NodeItem): - def __init__(self): - super(ScrewPump, self).__init__("ScrewPump", parent=None) - - -class SelectableCompressor(NodeItem): - def __init__(self): - super(SelectableCompressor, self).__init__("SelectableCompressor", parent=None) - - -class SelectableFan(NodeItem): - def __init__(self): - super(SelectableFan, self).__init__("SelectableFan", parent=None) - - -class SinglePassHeat(NodeItem): - def __init__(self): - super(SinglePassHeat, self).__init__("SinglePassHeat", parent=None) - - -class SpiralHeatExchanger(NodeItem): - def __init__(self): - super(SpiralHeatExchanger, self).__init__("SpiralHeatExchanger", parent=None) - - -class StraightTubersHeat(NodeItem): - def __init__(self): - super(StraightTubersHeat, self).__init__("StraightTubersHeat", parent=None) - - -class Tank(NodeItem): - def __init__(self): - super(Tank, self).__init__("Tank", parent=None) - - -class TurbinePump(NodeItem): - def __init__(self): - super(TurbinePump, self).__init__("TurbinePump", parent=None) - - -class UTubeHeatExchanger(NodeItem): - def __init__(self): - super(UTubeHeatExchanger, self).__init__("UTubeHeatExchanger", parent=None) - - -class VaccumPump(NodeItem): - def __init__(self): - super(VaccumPump, self).__init__("VaccumPump", parent=None) - - -class VerticalPump(NodeItem): - def __init__(self): - super(VerticalPump, self).__init__("VerticalPump", parent=None) - - -class VerticalVessel(NodeItem): - def __init__(self): - super(VerticalVessel, self).__init__("VerticalVessel", parent=None) - - -class WastewaterTreatment(NodeItem): - def __init__(self): - super(WastewaterTreatment, self).__init__("WastewaterTreatment", parent=None) +
\ No newline at end of file diff --git a/src/main/python/utils/app.py b/src/main/python/utils/app.py index 5d85cb7..9812fda 100644 --- a/src/main/python/utils/app.py +++ b/src/main/python/utils/app.py @@ -8,6 +8,7 @@ from json import JSONEncoder, dumps, loads, dump, load app = ApplicationContext() settings = QSettings(QSettings.IniFormat, QSettings.UserScope ,"FOSSEE", "Chemical-PFD") +version = app.build_settings['version'] def fileImporter(file): # Helper function to fetch files from src/main/resources @@ -49,4 +50,7 @@ class JSON_Typer(JSONEncoder): return JSON_Encoder._encode(obj) def encode(self, obj): - return super(JSON_Typer, self).encode(self._encode(obj))
\ No newline at end of file + return super(JSON_Typer, self).encode(self._encode(obj)) + +shapeGrips = {} +lines = {}
\ No newline at end of file diff --git a/src/main/python/utils/canvas.py b/src/main/python/utils/canvas.py index a83aeb2..3f9cee5 100644 --- a/src/main/python/utils/canvas.py +++ b/src/main/python/utils/canvas.py @@ -6,7 +6,7 @@ from PyQt5.QtWidgets import (QFileDialog, QApplication, QHBoxLayout, QMenu, from . import dialogs from .graphics import customView, customScene from .data import paperSizes, ppiList, sheetDimensionList -from .app import dumps, loads, JSON_Typer +from .app import shapeGrips, lines import shapes @@ -129,9 +129,7 @@ class canvas(QWidget): "canvasSize": self._canvasSize, "ObjectName": self.objectName(), "symbols": [i for i in self.painter.items() if isinstance(i, shapes.NodeItem)], - "lines": [i for i in self.painter.items() if isinstance(i, shapes.Line)], - # "lineLabels": [i.__getstate__() for i in self.painter.items() if isinstance(i, shapes.LineLabel)], - # "itemLabels": [i.__getstate__() for i in self.painter.items() if isinstance(i, shapes.itemLabel)] + "lines": sorted([i for i in self.painter.items() if isinstance(i, shapes.Line)], key = lambda x: 1 if x.refLine else 0) } def __setstate__(self, dict): @@ -144,17 +142,43 @@ class canvas(QWidget): graphic.__setstate__(dict = item) self.painter.addItem(graphic) graphic.setPos(*item['pos']) + graphic.updateLineGripItem() + graphic.updateSizeGripItem() + for gripitem in item['lineGripItems']: + shapeGrips[gripitem[0]] = (graphic, gripitem[1]) + if item['label']: + graphicLabel = shapes.ItemLabel(pos = QPointF(*item['label']['pos']), parent = graphic) + graphicLabel.__setstate__(item['label']) + self.painter.addItem(graphicLabel) for item in dict['lines']: line = shapes.Line(QPointF(*item['startPoint']), QPointF(*item['endPoint'])) + lines[item['id']] = line line.__setstate__(dict = item) self.painter.addItem(line) - + graphic, index = shapeGrips[item['startGripItem']] + line.startGripItem = graphic.lineGripItems[index] + graphic.lineGripItems[index].line = line + if item['endGripItem']: + graphic, index = shapeGrips[item['endGripItem']] + line.endGripItem = graphic.lineGripItems[index] + graphic.lineGripItems[index].line = line + else: + line.refLine = lines[item['refLine']] + lines[item['refLine']].midLines.append(line) + line.refIndex = item['refIndex'] + for label in item['label']: + labelItem = shapes.LineLabel(QPointF(*label['pos']), line) + line.label.append(labelItem) + labelItem.__setstate__(label) + self.painter.addItem(labelItem) + line.updateLine() + line.addGrabber() + + shapeGrips.clear() + lines.clear() self.painter.advance() - # for item in dict['lineLabels']: - # pass - # for item in dict['itemLabels']: - # pass +
\ No newline at end of file diff --git a/src/main/python/utils/fileWindow.py b/src/main/python/utils/fileWindow.py index 04ed81a..663a7f3 100644 --- a/src/main/python/utils/fileWindow.py +++ b/src/main/python/utils/fileWindow.py @@ -3,13 +3,13 @@ from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import (QFileDialog, QHBoxLayout, QMdiSubWindow, QMenu, QPushButton, QSizePolicy, QSplitter, QWidget, QStyle) - +from os import path from . import dialogs from .graphics import customView from .canvas import canvas from .tabs import customTabWidget from .undo import resizeCommand -from .app import dump, loads, JSON_Typer +from .app import dump, loads, JSON_Typer, version class fileWindow(QMdiSubWindow): @@ -221,6 +221,8 @@ class fileWindow(QMdiSubWindow): # 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[0]: + self.setObjectName(path.basename(name[0]).split(".")[0]) + self.setWindowTitle(self.objectName()) with open(name[0],'w') as file: dump(self, file, indent=4, cls=JSON_Typer) return True @@ -241,13 +243,14 @@ class fileWindow(QMdiSubWindow): def __getstate__(self) -> dict: return { "_classname_": self.__class__.__name__, + "version": version, "ObjectName": self.objectName(), "tabs": [i.__getstate__() for i in self.tabList] } def __setstate__(self, dict): - self.setObjectName = dict['ObjectName'] - self.setWindowTitle = dict['ObjectName'] + self.setObjectName(dict['ObjectName']) + self.setWindowTitle(dict['ObjectName']) for i in dict['tabs']: diagram = self.newDiagram(i['ObjectName']) diagram.__setstate__(i) diff --git a/src/main/python/utils/tabs.py b/src/main/python/utils/tabs.py index eab056a..5196557 100644 --- a/src/main/python/utils/tabs.py +++ b/src/main/python/utils/tabs.py @@ -1,11 +1,12 @@ -from PyQt5.QtWidgets import QTabBar, QPushButton, QTabWidget -from PyQt5.QtCore import pyqtSignal, QSize +from PyQt5.QtWidgets import QTabBar, QPushButton, QTabWidget, QInputDialog +from PyQt5.QtCore import pyqtSignal, QSize, Qt class tabBarPlus(QTabBar): """ Just implemented to overload resize and layout change to emit a signal """ layoutChanged = pyqtSignal() + nameChanged = pyqtSignal(int, str) def resizeEvent(self, event): super().resizeEvent(event) self.layoutChanged.emit() @@ -14,7 +15,17 @@ class tabBarPlus(QTabBar): super().tabLayoutChange() self.layoutChanged.emit() - + def mouseDoubleClickEvent(self, event): + if event.button() != Qt.LeftButton: + return super().mouseDoubleClickEvent() + index = self.currentIndex() + newName, bool = QInputDialog.getText(self, "Change Diagram Name", "Enter new name", + text = self.tabText(index)) + if bool: + self.setTabText(index, newName) + self.nameChanged.emit(index, newName) + + class customTabWidget(QTabWidget): """ QTabWidget with a new tab button, also catches layoutChange signal by @@ -50,6 +61,7 @@ class customTabWidget(QTabWidget): self.tab.layoutChanged.connect(self.movePlusButton) #connect layout change # to dynamically move the button. + self.tab.nameChanged.connect(self.changeWidgetName) #set custom stylesheet for the widget area self.setStyleSheet("""QTabWidget::pane { @@ -68,4 +80,7 @@ class customTabWidget(QTabWidget): 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 + self.plusButton.move(size-3, h) + + def changeWidgetName(self, index, newName): + self.widget(index).setObjectName(newName)
\ No newline at end of file diff --git a/src/main/python/utils/toolbar.py b/src/main/python/utils/toolbar.py index af6feae..7883136 100644 --- a/src/main/python/utils/toolbar.py +++ b/src/main/python/utils/toolbar.py @@ -20,6 +20,7 @@ class toolbar(QDockWidget): def __init__(self, parent = None): super(toolbar, self).__init__(parent) self.toolbarButtonDict = dict() #initializes empty dict to store toolbar buttons + self.toolbarButtonClassList = [] self.toolbarItems(toolbarItems.keys()) #creates all necessary buttons self.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) @@ -59,8 +60,9 @@ class toolbar(QDockWidget): def populateToolbar(self, list): #called everytime the button box needs to be updated(incase of a filter) self.clearLayout() #clears layout - for item in list: - self.diagAreaLayout.addWidget(self.toolbarButtonDict[item]) + for itemClass in list: + for item in self.toolbarButtonDict[itemClass].keys(): + self.diagAreaLayout.addWidget(self.toolbarButtonDict[itemClass][item]) self.resize() def searchQuery(self): @@ -86,13 +88,16 @@ class toolbar(QDockWidget): self.diagAreaWidget.setLayout(self.diagAreaLayout) self.diagArea.setWidget(self.diagAreaWidget) - def toolbarItems(self, items): + def toolbarItems(self, itemClasses): #helper functions to create required buttons - for item in items: - obj = toolbarItems[item] - button = toolbarButton(self, obj) - button.clicked.connect(lambda : self.toolbuttonClicked.emit(obj)) - self.toolbarButtonDict[item] = button + for itemClass in itemClasses: + self.toolbarButtonDict[itemClass] = {} + self.toolbarButtonClassList.append(itemClass) + for item in toolbarItems[itemClass].keys(): + obj = toolbarItems[itemClass][item] + button = toolbarButton(self, obj) + button.clicked.connect(lambda : self.toolbuttonClicked.emit(obj)) + self.toolbarButtonDict[itemClass][item] = button @property def toolbarItemList(self): diff --git a/src/main/python/utils/undo.py b/src/main/python/utils/undo.py index 7979bf3..b060550 100644 --- a/src/main/python/utils/undo.py +++ b/src/main/python/utils/undo.py @@ -31,12 +31,13 @@ class addCommand(QUndoCommand): def undo(self): self.scene.removeItem(self.diagramItem) self.scene.update() + self.scene.advance() def redo(self): self.scene.addItem(self.diagramItem) self.diagramItem.setPos(self.itemPos) self.scene.clearSelection() - self.scene.update() + self.scene.advance() class deleteCommand(QUndoCommand): """ |