Browse Source

Fix creating a jobname after loading a file

Moves jobname creation out of qml and into python.
CURA-1619
fieldOfView 8 years ago
parent
commit
bb18bf6a30

+ 0 - 15
cura/CuraApplication.py

@@ -436,21 +436,6 @@ class CuraApplication(QtApplication):
         self._platform_activity = True if count > 0 else False
         self.activityChanged.emit()
 
-    @pyqtSlot(str)
-    def setJobName(self, name):
-        # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its
-        # extension. This cuts the extension off if necessary.
-        name = os.path.splitext(name)[0]
-        if self._job_name != name:
-            self._job_name = name
-            self.jobNameChanged.emit()
-
-    jobNameChanged = pyqtSignal()
-
-    @pyqtProperty(str, notify = jobNameChanged)
-    def jobName(self):
-        return self._job_name
-
     # Remove all selected objects from the scene.
     @pyqtSlot()
     def deleteSelection(self):

+ 52 - 4
cura/PrintInformation.py

@@ -1,14 +1,17 @@
 # Copyright (c) 2015 Ultimaker B.V.
 # Cura is released under the terms of the AGPLv3 or higher.
 
-from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
+from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot
 
 from UM.Application import Application
 from UM.Qt.Duration import Duration
+from UM.Preferences import Preferences
 
 import math
+import os.path
+import unicodedata
 
-##  A class for processing and calculating minimum, current and maximum print time.
+##  A class for processing and calculating minimum, current and maximum print time as well as managing the job name
 #
 #   This class contains all the logic relating to calculation and slicing for the
 #   time/quality slider concept. It is a rather tricky combination of event handling
@@ -22,6 +25,8 @@ import math
 #   - When that is done, we update the minimum print time and start the final slice pass, the "high quality settings pass".
 #   - When the high quality pass is done, we update the maximum print time.
 #
+#   This class also mangles the current machine name and the filename of the first loaded mesh into a job name.
+#   This job name is requested by the JobSpecs qml file.
 class PrintInformation(QObject):
     class SlicePass:
         CurrentSettings = 1
@@ -45,14 +50,17 @@ class PrintInformation(QObject):
         if self._backend:
             self._backend.printDurationMessage.connect(self._onPrintDurationMessage)
 
+        self._job_name = ""
+        Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
+
     currentPrintTimeChanged = pyqtSignal()
-    
+
     @pyqtProperty(Duration, notify = currentPrintTimeChanged)
     def currentPrintTime(self):
         return self._current_print_time
 
     materialAmountChanged = pyqtSignal()
-    
+
     @pyqtProperty(float, notify = materialAmountChanged)
     def materialAmount(self):
         return self._material_amount
@@ -66,3 +74,43 @@ class PrintInformation(QObject):
         r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2
         self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2)
         self.materialAmountChanged.emit()
+
+    @pyqtSlot(str)
+    def setJobName(self, name):
+        # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its
+        # extension. This cuts the extension off if necessary.
+        name = os.path.splitext(name)[0]
+        if self._job_name != name:
+            self._job_name = name
+            self.jobNameChanged.emit()
+
+    jobNameChanged = pyqtSignal()
+
+    @pyqtProperty(str, notify = jobNameChanged)
+    def jobName(self):
+        return self._job_name
+
+    @pyqtSlot(str, result = str)
+    def createJobName(self, base_name):
+        base_name = self._stripAccents(base_name)
+        if Preferences.getInstance().getValue("cura/jobname_prefix"):
+            return self._abbr_machine + "_" + base_name
+        else:
+            return base_name
+
+    def _onGlobalStackChanged(self):
+        global_stack_name = Application.getInstance().getGlobalContainerStack().getName()
+        split_name = global_stack_name.split(" ")
+        abbr_machine = ""
+        for word in split_name:
+            if(word.lower() == "ultimaker"):
+                abbr_machine += "UM"
+            elif word.isdigit():
+                abbr_machine += word
+            else:
+                abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0]
+
+        self._abbr_machine = abbr_machine
+
+    def _stripAccents(self, str):
+       return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')

+ 2 - 2
resources/qml/Cura.qml

@@ -93,7 +93,7 @@ UM.MainWindow
                     text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File");
                     enabled: UM.Selection.hasSelection;
                     iconName: "document-save-as";
-                    onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", Printer.jobName, { "filter_by_machine": false });
+                    onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false });
                 }
                 Menu
                 {
@@ -109,7 +109,7 @@ UM.MainWindow
                         MenuItem
                         {
                             text: model.description;
-                            onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id, Printer.jobName, { "filter_by_machine": false });
+                            onTriggered: UM.OutputDeviceManager.requestWriteToDevice(model.id, PrintInformation.jobName, { "filter_by_machine": false });
                         }
                         onObjectAdded: saveAllMenu.insertItem(index, object)
                         onObjectRemoved: saveAllMenu.removeItem(object)

+ 24 - 61
resources/qml/JobSpecs.qml

@@ -10,62 +10,25 @@ import UM 1.1 as UM
 import Cura 1.0 as Cura
 
 Rectangle {
-    id: base;
+    id: base
 
-    property bool activity: Printer.getPlatformActivity;
+    property bool activity: Printer.getPlatformActivity
     property string fileBaseName
     property variant activeMachineName: Cura.MachineManager.activeMachineName
 
     onActiveMachineNameChanged:
     {
-        base.createFileName()
+        printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
     }
 
     UM.I18nCatalog { id: catalog; name:"cura"}
 
-    property variant printDuration: PrintInformation.currentPrintTime;
-    property real printMaterialAmount: PrintInformation.materialAmount;
+    property variant printDuration: PrintInformation.currentPrintTime
+    property real printMaterialAmount: PrintInformation.materialAmount
 
     height: childrenRect.height
     color: "transparent"
 
-    function createFileName()
-    {
-        var splitMachineName = Cura.MachineManager.activeMachineName.split(" ")
-        var abbrMachine = "";
-        if ((UM.Preferences.getValue("cura/jobname_prefix")))
-        {
-            for (var i = 0; i < splitMachineName.length; i++)
-            {
-                if (splitMachineName[i].search(/ultimaker/i) != -1)
-                {
-                    abbrMachine += "UM";
-                }
-                else
-                {
-                    if (splitMachineName[i].charAt(0).search(/[0-9]/g) == -1)
-                    {
-                        abbrMachine += splitMachineName[i].charAt(0);
-                    }
-                }
-            }
-            var regExpAdditives = /[0-9\+]/g;
-            var resultAdditives = splitMachineName[i].match(regExpAdditives);
-            if (resultAdditives != null)
-            {
-                for (var j = 0; j < resultAdditives.length; j++)
-                {
-                    abbrMachine += resultAdditives[j];
-                }
-            }
-            printJobTextfield.text = abbrMachine + "_" + base.fileBaseName;
-        }
-        else
-        {
-            printJobTextfield.text = base.fileBaseName;
-        }
-    }
-
     Connections
     {
         target: backgroundItem
@@ -78,20 +41,20 @@ Rectangle {
     onActivityChanged: {
         if (activity == true && base.fileBaseName == ''){
             //this only runs when you open a file from the terminal (or something that works the same way; for example when you drag a file on the icon in MacOS or use 'open with' on Windows)
-            base.fileBaseName = Printer.jobName //it gets the fileBaseName from CuraApplication.py because this saves the filebase when the file is opened using the terminal (or something alike)
-            base.createFileName()
+            base.fileBaseName = PrintInformation.jobName; //get the fileBaseName from PrintInformation.py because this saves the filebase when the file is opened using the terminal (or something alike)
+            printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
         }
         if (activity == true && base.fileBaseName != ''){
             //this runs in all other cases where there is a mesh on the buildplate (activity == true). It uses the fileBaseName from the hasMesh signal
-            base.createFileName()
+            printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
         }
         if (activity == false){
             //When there is no mesh in the buildplate; the printJobTextField is set to an empty string so it doesn't set an empty string as a jobName (which is later used for saving the file)
-            printJobTextfield.text = ''
+            printJobTextfield.text = '';
         }
     }
 
-    Rectangle 
+    Rectangle
     {
         id: jobNameRow
         anchors.top: parent.top
@@ -112,22 +75,22 @@ Rectangle {
                 width: UM.Theme.getSize("save_button_specs_icons").width
                 height: UM.Theme.getSize("save_button_specs_icons").height
 
-                onClicked: 
+                onClicked:
                 {
-                    printJobTextfield.selectAll()
-                    printJobTextfield.focus = true
+                    printJobTextfield.selectAll();
+                    printJobTextfield.focus = true;
                 }
                 style: ButtonStyle
                 {
                     background: Rectangle
                     {
                         color: "transparent"
-                        UM.RecolorImage 
+                        UM.RecolorImage
                         {
-                            width: UM.Theme.getSize("save_button_specs_icons").width
-                            height: UM.Theme.getSize("save_button_specs_icons").height
-                            sourceSize.width: width
-                            sourceSize.height: width
+                            width: UM.Theme.getSize("save_button_specs_icons").width;
+                            height: UM.Theme.getSize("save_button_specs_icons").height;
+                            sourceSize.width: width;
+                            sourceSize.height: width;
                             color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("text");
                             source: UM.Theme.getIcon("pencil");
                         }
@@ -147,15 +110,15 @@ Rectangle {
                 text: ''
                 horizontalAlignment: TextInput.AlignRight
                 onTextChanged: {
-                    Printer.setJobName(text)
+                    PrintInformation.setJobName(text);
                 }
                 onEditingFinished: {
                     if (printJobTextfield.text != ''){
-                        printJobTextfield.focus = false
+                        printJobTextfield.focus = false;
                     }
                 }
                 validator: RegExpValidator {
-                    regExp: /^[^\\ \/ \.]*$/
+                    regExp: /^[^\\ \/ \*\?\|\[\]]*$/
                 }
                 style: TextFieldStyle{
                     textColor: UM.Theme.getColor("setting_control_text");
@@ -200,7 +163,7 @@ Rectangle {
                 sourceSize.width: width
                 sourceSize.height: width
                 color: UM.Theme.getColor("text_subtext")
-                source: UM.Theme.getIcon("print_time");
+                source: UM.Theme.getIcon("print_time")
             }
             Label{
                 id: timeSpec
@@ -221,7 +184,7 @@ Rectangle {
                 sourceSize.width: width
                 sourceSize.height: width
                 color: UM.Theme.getColor("text_subtext")
-                source: UM.Theme.getIcon("category_material");
+                source: UM.Theme.getIcon("category_material")
             }
             Label{
                 id: lengthSpec
@@ -229,7 +192,7 @@ Rectangle {
                 anchors.verticalCenter: parent.verticalCenter
                 font: UM.Theme.getFont("small")
                 color: UM.Theme.getColor("text_subtext")
-                text: base.printMaterialAmount <= 0 ? catalog.i18nc("@label", "0.0 m") : catalog.i18nc("@label", "%1 m").arg(base.printMaterialAmount)
+                text: catalog.i18nc("@label", "%1 m").arg(base.printMaterialAmount > 0 ? base.printMaterialAmount : 0)
             }
         }
     }

+ 1 - 1
resources/qml/SaveButton.qml

@@ -98,7 +98,7 @@ Rectangle {
             text: UM.OutputDeviceManager.activeDeviceShortDescription
             onClicked:
             {
-                UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, Printer.jobName, { "filter_by_machine": true })
+                UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName, { "filter_by_machine": true })
             }
 
             style: ButtonStyle {