Browse Source

CURA-4525 Send all build plate gcodes to printer at one press of the button :-)

Jack Ha 7 years ago
parent
commit
8e5e555344

+ 18 - 1
cura/CuraApplication.py

@@ -258,6 +258,7 @@ class CuraApplication(QtApplication):
         self._i18n_catalog = i18nCatalog("cura")
 
         self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity)
+        self.getController().getScene().sceneChanged.connect(self.updateMaxBuildPlate)  # it may be a bit inefficient when changing a lot simultaneously
         self.getController().toolOperationStopped.connect(self._onToolOperationStopped)
         self.getController().contextMenuRequested.connect(self._onContextMenuRequested)
 
@@ -1523,7 +1524,7 @@ class CuraApplication(QtApplication):
     @pyqtSlot()
     def newBuildPlate(self):
         Logger.log("d", "New build plate")
-        self._num_build_plates += 1
+        #self._num_build_plates += 1
         self.numBuildPlatesChanged.emit()
 
     @pyqtProperty(int, notify = numBuildPlatesChanged)
@@ -1533,3 +1534,19 @@ class CuraApplication(QtApplication):
     @pyqtProperty(int, notify = activeBuildPlateChanged)
     def activeBuildPlate(self):
         return self._active_build_plate
+
+    def updateMaxBuildPlate(self, source):
+        if not issubclass(type(source), SceneNode):
+            return
+        num_build_plates = self._calcMaxBuildPlate()
+        if num_build_plates != self._num_build_plates:
+            self._num_build_plates = num_build_plates
+            self.numBuildPlatesChanged.emit()
+
+    def _calcMaxBuildPlate(self):
+        max_build_plate = 0
+        for node in DepthFirstIterator(self.getController().getScene().getRoot()):
+            if node.callDecoration("isSliceable"):
+                build_plate_number = node.callDecoration("getBuildPlateNumber")
+                max_build_plate = max(build_plate_number, max_build_plate)
+        return max_build_plate

+ 1 - 1
cura/GCodeListDecorator.py

@@ -4,7 +4,7 @@ from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
 class GCodeListDecorator(SceneNodeDecorator):
     def __init__(self):
         super().__init__()
-        self._gcode_list = []
+        self._gcode_list = {}  # []
 
     def getGCodeList(self):
         return self._gcode_list

+ 10 - 6
plugins/CuraEngineBackend/CuraEngineBackend.py

@@ -230,7 +230,9 @@ class CuraEngineBackend(QObject, Backend):
         self.processingProgress.emit(0.0)
         self.backendStateChange.emit(BackendState.NotStarted)
 
-        self._scene.gcode_list = []
+        if not hasattr(self._scene, "gcode_list"):
+            self._scene.gcode_list = {}
+        self._scene.gcode_list[build_plate_to_be_sliced] = []  #[] indexed by build plate number
         self._slicing = True
         self.slicingStarted.emit()
 
@@ -370,7 +372,7 @@ class CuraEngineBackend(QObject, Backend):
                 self.backendStateChange.emit(BackendState.Disabled)
             gcode_list = node.callDecoration("getGCodeList")
             if gcode_list is not None:
-                self._scene.gcode_list = gcode_list
+                self._scene.gcode_list[node.callDecoration("getBuildPlateNumber")] = gcode_list
 
         if self._use_timer == enable_timer:
             return self._use_timer
@@ -546,14 +548,16 @@ class CuraEngineBackend(QObject, Backend):
         self.backendStateChange.emit(BackendState.Done)
         self.processingProgress.emit(1.0)
 
-        for line in self._scene.gcode_list:
+        gcode_list = self._scene.gcode_list[self._start_slice_job_build_plate]
+        for index, line in enumerate(gcode_list):
             replaced = line.replace("{print_time}", str(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.ISO8601)))
             replaced = replaced.replace("{filament_amount}", str(Application.getInstance().getPrintInformation().materialLengths))
             replaced = replaced.replace("{filament_weight}", str(Application.getInstance().getPrintInformation().materialWeights))
             replaced = replaced.replace("{filament_cost}", str(Application.getInstance().getPrintInformation().materialCosts))
             replaced = replaced.replace("{jobname}", str(Application.getInstance().getPrintInformation().jobName))
 
-            self._scene.gcode_list[self._scene.gcode_list.index(line)] = replaced
+            #gcode_list[gcode_list.index(line)] = replaced
+            gcode_list[index] = replaced
 
         self._slicing = False
         #self._need_slicing = False
@@ -576,14 +580,14 @@ class CuraEngineBackend(QObject, Backend):
     #
     #   \param message The protobuf message containing g-code, encoded as UTF-8.
     def _onGCodeLayerMessage(self, message):
-        self._scene.gcode_list.append(message.data.decode("utf-8", "replace"))
+        self._scene.gcode_list[self._start_slice_job_build_plate].append(message.data.decode("utf-8", "replace"))
 
     ##  Called when a g-code prefix message is received from the engine.
     #
     #   \param message The protobuf message containing the g-code prefix,
     #   encoded as UTF-8.
     def _onGCodePrefixMessage(self, message):
-        self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace"))
+        self._scene.gcode_list[self._start_slice_job_build_plate].insert(0, message.data.decode("utf-8", "replace"))
 
     ##  Creates a new socket connection.
     def _createSocket(self):

+ 22 - 8
plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py

@@ -254,6 +254,10 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
         self._selected_printer = self._automatic_printer  # reset to default option
         self._request_job = [nodes, file_name, filter_by_machine, file_handler, kwargs]
 
+        # the build plates to be sent
+        self._job_list = list(getattr(Application.getInstance().getController().getScene(), "gcode_list").keys())
+        Logger.log("d", "build plates to be sent to printer: %s", (self._job_list))
+
         if self._stage != OutputStage.ready:
             if self._error_message:
                 self._error_message.hide()
@@ -263,12 +267,14 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
             self._error_message.show()
             return
 
+        self._add_build_plate_number = len(self._job_list) > 1
         if len(self._printers) > 1:
             self.spawnPrintView()  # Ask user how to print it.
         elif len(self._printers) == 1:
             # If there is only one printer, don't bother asking.
             self.selectAutomaticPrinter()
             self.sendPrintJob()
+
         else:
             # Cluster has no printers, warn the user of this.
             if self._error_message:
@@ -283,28 +289,34 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
     @pyqtSlot()
     def sendPrintJob(self):
         nodes, file_name, filter_by_machine, file_handler, kwargs = self._request_job
-        require_printer_name = self._selected_printer["unique_name"]
+        output_build_plate_number = self._job_list.pop(0)
+        gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list")[output_build_plate_number]
 
         self._send_gcode_start = time.time()
-        Logger.log("d", "Sending print job [%s] to host..." % file_name)
+        Logger.log("d", "Sending print job [%s] to host, build plate [%s]..." % (file_name, output_build_plate_number))
 
         if self._stage != OutputStage.ready:
             Logger.log("d", "Unable to send print job as the state is %s", self._stage)
             raise OutputDeviceError.DeviceBusyError()
         self._stage = OutputStage.uploading
 
-        self._file_name = "%s.gcode.gz" % file_name
+        if self._add_build_plate_number:
+            self._file_name = "%s_%d.gcode.gz" % (file_name, output_build_plate_number)
+        else:
+            self._file_name = "%s.gcode.gz" % (file_name)
         self._showProgressMessage()
 
-        new_request = self._buildSendPrintJobHttpRequest(require_printer_name)
+        require_printer_name = self._selected_printer["unique_name"]
+
+        new_request = self._buildSendPrintJobHttpRequest(require_printer_name, gcode)
         if new_request is None or self._stage != OutputStage.uploading:
             return
         self._request = new_request
         self._reply = self._manager.post(self._request, self._multipart)
         self._reply.uploadProgress.connect(self._onUploadProgress)
-        # See _finishedPostPrintJobRequest()
+        # See _finishedPrintJobPostRequest()
 
-    def _buildSendPrintJobHttpRequest(self, require_printer_name):
+    def _buildSendPrintJobHttpRequest(self, require_printer_name, gcode):
         api_url = QUrl(self._api_base_uri + "print_jobs/")
         request = QNetworkRequest(api_url)
         # Create multipart request and add the g-code.
@@ -313,9 +325,8 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
         # Add gcode
         part = QHttpPart()
         part.setHeader(QNetworkRequest.ContentDispositionHeader,
-                       'form-data; name="file"; filename="%s"' % self._file_name)
+                       'form-data; name="file"; filename="%s"' % (self._file_name))
 
-        gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list")
         compressed_gcode = self._compressGcode(gcode)
         if compressed_gcode is None:
             return None     # User aborted print, so stop trying.
@@ -401,6 +412,9 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
 
         self._cleanupRequest()
 
+        if self._job_list:  # start sending next job
+            self.sendPrintJob()
+
     def _showRequestFailedMessage(self, reply):
         if reply is not None:
             Logger.log("w", "Unable to send print job to group {cluster_name}: {error_string} ({error})".format(