Fix creating a jobname after loading a file

Moves jobname creation out of qml and into python.
CURA-1619
This commit is contained in:
fieldOfView 2016-06-02 16:38:06 +02:00
parent 14a8b8a1a4
commit bb18bf6a30
5 changed files with 79 additions and 83 deletions

View file

@ -436,21 +436,6 @@ class CuraApplication(QtApplication):
self._platform_activity = True if count > 0 else False self._platform_activity = True if count > 0 else False
self.activityChanged.emit() 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. # Remove all selected objects from the scene.
@pyqtSlot() @pyqtSlot()
def deleteSelection(self): def deleteSelection(self):

View file

@ -1,14 +1,17 @@
# Copyright (c) 2015 Ultimaker B.V. # Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher. # 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.Application import Application
from UM.Qt.Duration import Duration from UM.Qt.Duration import Duration
from UM.Preferences import Preferences
import math 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 # 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 # 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 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. # - 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 PrintInformation(QObject):
class SlicePass: class SlicePass:
CurrentSettings = 1 CurrentSettings = 1
@ -45,14 +50,17 @@ class PrintInformation(QObject):
if self._backend: if self._backend:
self._backend.printDurationMessage.connect(self._onPrintDurationMessage) self._backend.printDurationMessage.connect(self._onPrintDurationMessage)
self._job_name = ""
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
currentPrintTimeChanged = pyqtSignal() currentPrintTimeChanged = pyqtSignal()
@pyqtProperty(Duration, notify = currentPrintTimeChanged) @pyqtProperty(Duration, notify = currentPrintTimeChanged)
def currentPrintTime(self): def currentPrintTime(self):
return self._current_print_time return self._current_print_time
materialAmountChanged = pyqtSignal() materialAmountChanged = pyqtSignal()
@pyqtProperty(float, notify = materialAmountChanged) @pyqtProperty(float, notify = materialAmountChanged)
def materialAmount(self): def materialAmount(self):
return self._material_amount return self._material_amount
@ -66,3 +74,43 @@ class PrintInformation(QObject):
r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2 r = Application.getInstance().getGlobalContainerStack().getProperty("material_diameter", "value") / 2
self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2) self._material_amount = round((amount / (math.pi * r ** 2)) / 1000, 2)
self.materialAmountChanged.emit() 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')

View file

@ -93,7 +93,7 @@ UM.MainWindow
text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File"); text: catalog.i18nc("@action:inmenu menubar:file", "&Save Selection to File");
enabled: UM.Selection.hasSelection; enabled: UM.Selection.hasSelection;
iconName: "document-save-as"; 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 Menu
{ {
@ -109,7 +109,7 @@ UM.MainWindow
MenuItem MenuItem
{ {
text: model.description; 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) onObjectAdded: saveAllMenu.insertItem(index, object)
onObjectRemoved: saveAllMenu.removeItem(object) onObjectRemoved: saveAllMenu.removeItem(object)

View file

@ -10,62 +10,25 @@ import UM 1.1 as UM
import Cura 1.0 as Cura import Cura 1.0 as Cura
Rectangle { Rectangle {
id: base; id: base
property bool activity: Printer.getPlatformActivity; property bool activity: Printer.getPlatformActivity
property string fileBaseName property string fileBaseName
property variant activeMachineName: Cura.MachineManager.activeMachineName property variant activeMachineName: Cura.MachineManager.activeMachineName
onActiveMachineNameChanged: onActiveMachineNameChanged:
{ {
base.createFileName() printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
} }
UM.I18nCatalog { id: catalog; name:"cura"} UM.I18nCatalog { id: catalog; name:"cura"}
property variant printDuration: PrintInformation.currentPrintTime; property variant printDuration: PrintInformation.currentPrintTime
property real printMaterialAmount: PrintInformation.materialAmount; property real printMaterialAmount: PrintInformation.materialAmount
height: childrenRect.height height: childrenRect.height
color: "transparent" 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 Connections
{ {
target: backgroundItem target: backgroundItem
@ -78,20 +41,20 @@ Rectangle {
onActivityChanged: { onActivityChanged: {
if (activity == true && base.fileBaseName == ''){ 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) //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.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)
base.createFileName() printJobTextfield.text = PrintInformation.createJobName(base.fileBaseName);
} }
if (activity == true && 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 //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){ 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) //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 id: jobNameRow
anchors.top: parent.top anchors.top: parent.top
@ -112,22 +75,22 @@ Rectangle {
width: UM.Theme.getSize("save_button_specs_icons").width width: UM.Theme.getSize("save_button_specs_icons").width
height: UM.Theme.getSize("save_button_specs_icons").height height: UM.Theme.getSize("save_button_specs_icons").height
onClicked: onClicked:
{ {
printJobTextfield.selectAll() printJobTextfield.selectAll();
printJobTextfield.focus = true printJobTextfield.focus = true;
} }
style: ButtonStyle style: ButtonStyle
{ {
background: Rectangle background: Rectangle
{ {
color: "transparent" color: "transparent"
UM.RecolorImage UM.RecolorImage
{ {
width: UM.Theme.getSize("save_button_specs_icons").width width: UM.Theme.getSize("save_button_specs_icons").width;
height: UM.Theme.getSize("save_button_specs_icons").height height: UM.Theme.getSize("save_button_specs_icons").height;
sourceSize.width: width sourceSize.width: width;
sourceSize.height: width sourceSize.height: width;
color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("text"); color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("text");
source: UM.Theme.getIcon("pencil"); source: UM.Theme.getIcon("pencil");
} }
@ -147,15 +110,15 @@ Rectangle {
text: '' text: ''
horizontalAlignment: TextInput.AlignRight horizontalAlignment: TextInput.AlignRight
onTextChanged: { onTextChanged: {
Printer.setJobName(text) PrintInformation.setJobName(text);
} }
onEditingFinished: { onEditingFinished: {
if (printJobTextfield.text != ''){ if (printJobTextfield.text != ''){
printJobTextfield.focus = false printJobTextfield.focus = false;
} }
} }
validator: RegExpValidator { validator: RegExpValidator {
regExp: /^[^\\ \/ \.]*$/ regExp: /^[^\\ \/ \*\?\|\[\]]*$/
} }
style: TextFieldStyle{ style: TextFieldStyle{
textColor: UM.Theme.getColor("setting_control_text"); textColor: UM.Theme.getColor("setting_control_text");
@ -200,7 +163,7 @@ Rectangle {
sourceSize.width: width sourceSize.width: width
sourceSize.height: width sourceSize.height: width
color: UM.Theme.getColor("text_subtext") color: UM.Theme.getColor("text_subtext")
source: UM.Theme.getIcon("print_time"); source: UM.Theme.getIcon("print_time")
} }
Label{ Label{
id: timeSpec id: timeSpec
@ -221,7 +184,7 @@ Rectangle {
sourceSize.width: width sourceSize.width: width
sourceSize.height: width sourceSize.height: width
color: UM.Theme.getColor("text_subtext") color: UM.Theme.getColor("text_subtext")
source: UM.Theme.getIcon("category_material"); source: UM.Theme.getIcon("category_material")
} }
Label{ Label{
id: lengthSpec id: lengthSpec
@ -229,7 +192,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
font: UM.Theme.getFont("small") font: UM.Theme.getFont("small")
color: UM.Theme.getColor("text_subtext") 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)
} }
} }
} }

View file

@ -98,7 +98,7 @@ Rectangle {
text: UM.OutputDeviceManager.activeDeviceShortDescription text: UM.OutputDeviceManager.activeDeviceShortDescription
onClicked: 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 { style: ButtonStyle {