This commit is contained in:
mobilityapplab 2020-02-04 14:00:45 -05:00
commit a91b0960fb
13 changed files with 238 additions and 31 deletions

View File

@ -23,6 +23,7 @@ set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")
set(CURA_CLOUD_API_ROOT "" CACHE STRING "Alternative Cura cloud API root")
set(CURA_CLOUD_API_VERSION "" CACHE STRING "Alternative Cura cloud API version")
set(CURA_CLOUD_ACCOUNT_API_ROOT "" CACHE STRING "Alternative Cura cloud account API version")
set(CURA_MARKETPLACE_ROOT "" CACHE STRING "Alternative Marketplace location")
configure_file(${CMAKE_SOURCE_DIR}/cura.desktop.in ${CMAKE_BINARY_DIR}/cura.desktop @ONLY)

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V.
# Copyright (c) 2020 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
# ---------

View File

@ -391,6 +391,8 @@ class CuraApplication(QtApplication):
SettingFunction.registerOperator("extruderValues", self._cura_formula_functions.getValuesInAllExtruders)
SettingFunction.registerOperator("resolveOrValue", self._cura_formula_functions.getResolveOrValue)
SettingFunction.registerOperator("defaultExtruderPosition", self._cura_formula_functions.getDefaultExtruderPosition)
SettingFunction.registerOperator("valueFromContainer", self._cura_formula_functions.getValueFromContainerAtIndex)
SettingFunction.registerOperator("extruderValueFromContainer", self._cura_formula_functions.getValueFromContainerAtIndexInExtruder)
# Adds all resources and container related resources.
def __addAllResourcesAndContainerResources(self) -> None:

View File

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V.
# Copyright (c) 2020 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
CuraAppName = "@CURA_APP_NAME@"
@ -9,3 +9,4 @@ CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False
CuraCloudAPIRoot = "@CURA_CLOUD_API_ROOT@"
CuraCloudAPIVersion = "@CURA_CLOUD_API_VERSION@"
CuraCloudAccountAPIRoot = "@CURA_CLOUD_ACCOUNT_API_ROOT@"
CuraMarketplaceRoot = "@CURA_MARKETPLACE_ROOT@"

View File

@ -133,6 +133,38 @@ class CuraFormulaFunctions:
context = self.createContextForDefaultValueEvaluation(global_stack)
return self.getResolveOrValue(property_key, context = context)
# Gets the value for the given setting key starting from the given container index.
def getValueFromContainerAtIndex(self, property_key: str, container_index: int,
context: Optional["PropertyEvaluationContext"] = None) -> Any:
machine_manager = self._application.getMachineManager()
global_stack = machine_manager.activeMachine
context = self.createContextForDefaultValueEvaluation(global_stack)
context.context["evaluate_from_container_index"] = container_index
return global_stack.getProperty(property_key, "value", context = context)
# Gets the extruder value for the given setting key starting from the given container index.
def getValueFromContainerAtIndexInExtruder(self, extruder_position: int, property_key: str, container_index: int,
context: Optional["PropertyEvaluationContext"] = None) -> Any:
machine_manager = self._application.getMachineManager()
global_stack = machine_manager.activeMachine
if extruder_position == -1:
extruder_position = int(machine_manager.defaultExtruderPosition)
global_stack = machine_manager.activeMachine
try:
extruder_stack = global_stack.extruderList[int(extruder_position)]
except IndexError:
Logger.log("w", "Value for %s of extruder %s was requested, but that extruder is not available. " % (property_key, extruder_position))
return None
context = self.createContextForDefaultValueEvaluation(extruder_stack)
context.context["evaluate_from_container_index"] = container_index
return self.getValueInExtruder(extruder_position, property_key, context)
# Creates a context for evaluating default values (skip the user_changes container).
def createContextForDefaultValueEvaluation(self, source_stack: "CuraContainerStack") -> "PropertyEvaluationContext":
context = PropertyEvaluationContext(source_stack)

View File

@ -800,7 +800,7 @@ class MachineManager(QObject):
definition_changes_container.setProperty("machine_extruder_count", "value", extruder_count)
self.updateDefaultExtruder()
self.updateNumberExtrudersEnabled()
self.numberExtrudersEnabledChanged.emit()
self.correctExtruderSettings()
# Check to see if any objects are set to print with an extruder that will no longer exist

View File

@ -118,7 +118,7 @@ class SimulationView(CuraView):
self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled."),
title = catalog.i18nc("@info:title", "Simulation View"))
self._slice_first_warning_message = Message(catalog.i18nc("@info:status", "Nothing is shown because you need to slice first."), title = catalog.i18nc("@info:title", "No layer data"))
self._slice_first_warning_message = Message(catalog.i18nc("@info:status", "Nothing is shown because you need to slice first."), title = catalog.i18nc("@info:title", "No layers to show"))
QtApplication.getInstance().engineCreatedSignal.connect(self._onEngineCreated)

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
<path d="M19,3H5A2.9,2.9,0,0,0,2,6V9a3.9,3.9,0,0,0,2,3.4V22H20V12.4A3.9,3.9,0,0,0,22,9V6A2.9,2.9,0,0,0,19,3ZM10,5h4V9a2,2,0,0,1-4,0ZM4,9V5H8V9A2,2,0,0,1,4,9ZM18,20H14V15H10v5H6V13a3.7,3.7,0,0,0,3-1.4A3.7,3.7,0,0,0,12,13a3.7,3.7,0,0,0,3-1.4A3.7,3.7,0,0,0,18,13ZM20,9a2,2,0,0,1-4,0V5h4Z" />
</svg>

After

Width:  |  Height:  |  Size: 364 B

View File

@ -14,17 +14,44 @@ Rectangle
Column
{
height: childrenRect.height + 2 * padding
spacing: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("default_margin").height
width: parent.width
padding: UM.Theme.getSize("wide_margin").height
Label
Item
{
id: heading
text: catalog.i18nc("@label", "Featured")
width: parent.width
color: UM.Theme.getColor("text_medium")
font: UM.Theme.getFont("large")
renderType: Text.NativeRendering
width: parent.width - parent.padding * 2
height: childrenRect.height
Label
{
id: heading
text: catalog.i18nc("@label", "Featured")
width: contentWidth
height: contentHeight
color: UM.Theme.getColor("text_medium")
font: UM.Theme.getFont("large")
renderType: Text.NativeRendering
}
UM.TooltipArea
{
width: childrenRect.width
height: childrenRect.height
anchors.right: parent.right
text: catalog.i18nc("@info:tooltip", "Go to Web Marketplace")
Label
{
text: "<a href='%2'>".arg(toolbox.getWebMarketplaceUrl("materials")) + catalog.i18nc("@label", "Search materials") + "</a>"
width: contentWidth
height: contentHeight
horizontalAlignment: Text.AlignRight
font: UM.Theme.getFont("default")
renderType: Text.NativeRendering
linkColor: UM.Theme.getColor("text_link")
onLinkActivated: Qt.openUrlExternally(link)
visible: toolbox.viewCategory === "material"
}
}
}
Grid
{

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018 Ultimaker B.V.
// Copyright (c) 2020 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
@ -51,32 +51,25 @@ Item
toolbox.viewPage = "overview"
}
}
}
ToolboxTabButton
{
id: installedTabButton
text: catalog.i18nc("@title:tab", "Installed")
active: toolbox.viewCategory == "installed"
enabled: !toolbox.isDownloading
anchors
ToolboxTabButton
{
right: parent.right
rightMargin: UM.Theme.getSize("default_margin").width
id: installedTabButton
text: catalog.i18nc("@title:tab", "Installed")
active: toolbox.viewCategory == "installed"
enabled: !toolbox.isDownloading
onClicked: toolbox.viewCategory = "installed"
width: UM.Theme.getSize("toolbox_header_tab").width + marketplaceNotificationIcon.width - UM.Theme.getSize("default_margin").width
}
onClicked: toolbox.viewCategory = "installed"
width: UM.Theme.getSize("toolbox_header_tab").width + marketplaceNotificationIcon.width - UM.Theme.getSize("default_margin").width
}
Cura.NotificationIcon
{
id: marketplaceNotificationIcon
visible: CuraApplication.getPackageManager().packagesWithUpdate.length > 0
anchors.right: installedTabButton.right
anchors.verticalCenter: installedTabButton.verticalCenter
anchors.right: bar.right
labelText:
{
const itemCount = CuraApplication.getPackageManager().packagesWithUpdate.length
@ -84,6 +77,33 @@ Item
}
}
UM.TooltipArea
{
id: webMarketplaceButtonTooltipArea
width: childrenRect.width
height: parent.height
text: catalog.i18nc("@info:tooltip", "Go to Web Marketplace")
anchors
{
right: parent.right
rightMargin: UM.Theme.getSize("default_margin").width
verticalCenter: parent.verticalCenter
}
onClicked: Qt.openUrlExternally(toolbox.getWebMarketplaceUrl("plugins"))
UM.RecolorImage
{
id: cloudMarketplaceButton
source: "../../images/shop.svg"
color: UM.Theme.getColor(webMarketplaceButtonTooltipArea.containsMouse ? "primary" : "text")
height: parent.height / 2
width: height
anchors.verticalCenter: parent.verticalCenter
sourceSize.width: width
sourceSize.height: height
}
}
ToolboxShadow
{
anchors.top: bar.bottom

View File

@ -63,7 +63,7 @@ class LicensePresenter(QObject):
self._package_models[self._current_package_idx]["accepted"] = False
self._checkNextPage()
def _initState(self, packages: Dict[str, Dict[str, str]]) -> None:
def _initState(self, packages: Dict[str, Dict[str, Any]]) -> None:
implicitly_accepted_count = 0

View File

@ -16,6 +16,7 @@ from UM.i18n import i18nCatalog
from UM.Version import Version
from cura import ApplicationMetadata
from cura.CuraApplication import CuraApplication
from cura.Machines.ContainerTree import ContainerTree
@ -31,6 +32,13 @@ if TYPE_CHECKING:
i18n_catalog = i18nCatalog("cura")
DEFAULT_MARKETPLACE_ROOT = "https://marketplace.ultimaker.com" # type: str
try:
from cura.CuraVersion import CuraMarketplaceRoot
except ImportError:
CuraMarketplaceRoot = DEFAULT_MARKETPLACE_ROOT
# todo Remove license and download dialog, use SyncOrchestrator instead
## Provides a marketplace for users to download plugins an materials
@ -766,6 +774,13 @@ class Toolbox(QObject, Extension):
def materialsGenericModel(self) -> PackagesModel:
return self._materials_generic_model
@pyqtSlot(str, result = str)
def getWebMarketplaceUrl(self, page: str) -> str:
root = CuraMarketplaceRoot
if root == "":
root = DEFAULT_MARKETPLACE_ROOT
return root + "/app/cura/" + page
# Filter Models:
# --------------------------------------------------------------------------
@pyqtSlot(str, str, str)

View File

@ -1,6 +1,16 @@
# Copyright (c) 2020 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import configparser
from typing import Tuple, List
import fnmatch # To filter files that we need to delete.
import io
import os # To get the path to check for hidden stacks to delete.
import urllib.parse # To get the container IDs from file names.
import re # To filter directories to search for hidden stacks to delete.
from UM.Logger import Logger
from UM.Resources import Resources # To get the path to check for hidden stacks to delete.
from UM.Version import Version # To sort folders by version number.
from UM.VersionUpgrade import VersionUpgrade
# Settings that were merged into one. Each one is a pair of settings. If both
@ -16,6 +26,102 @@ _removed_settings = {
}
class VersionUpgrade44to45(VersionUpgrade):
def __init__(self) -> None:
"""
Creates the version upgrade plug-in from 4.4 to 4.5.
In this case the plug-in will also check for stacks that need to be
deleted.
"""
# Only delete hidden stacks when upgrading from version 4.4. Not 4.3 or 4.5, just when you're starting out from 4.4.
# If you're starting from an earlier version, you can't have had the bug that produces too many hidden stacks (https://github.com/Ultimaker/Cura/issues/6731).
# If you're starting from a later version, the bug was already fixed.
data_storage_root = os.path.dirname(Resources.getDataStoragePath())
folders = set(os.listdir(data_storage_root)) # All version folders.
folders = set(filter(lambda p: re.fullmatch(r"\d+\.\d+", p), folders)) # Only folders with a correct version number as name.
folders.difference_update({os.path.basename(Resources.getDataStoragePath())}) # Remove current version from candidates (since the folder was just copied).
if folders:
latest_version = max(folders, key = Version) # Sort them by semantic version numbering.
if latest_version == "4.4":
self.removeHiddenStacks()
def removeHiddenStacks(self) -> None:
"""
If starting the upgrade from 4.4, this will remove any hidden printer
stacks from the configuration folder as well as all of the user profiles
and definition changes profiles.
This will ONLY run when upgrading from 4.4, not when e.g. upgrading from
4.3 to 4.6 (through 4.4). This is because it's to fix a bug
(https://github.com/Ultimaker/Cura/issues/6731) that occurred in 4.4
only, so only there will it have hidden stacks that need to be deleted.
If people upgrade from 4.3 they don't need to be deleted. If people
upgrade from 4.5 they have already been deleted previously or never got
the broken hidden stacks.
"""
Logger.log("d", "Removing all hidden container stacks.")
hidden_global_stacks = set() # Which global stacks have been found? We'll delete anything referred to by these. Set of stack IDs.
hidden_extruder_stacks = set() # Which extruder stacks refer to the hidden global profiles?
hidden_instance_containers = set() # Which instance containers are referred to by the hidden stacks?
exclude_directories = {"plugins"}
# First find all of the hidden container stacks.
data_storage = Resources.getDataStoragePath()
for root, dirs, files in os.walk(data_storage):
dirs[:] = [dir for dir in dirs if dir not in exclude_directories]
for filename in fnmatch.filter(files, "*.global.cfg"):
parser = configparser.ConfigParser(interpolation = None)
try:
parser.read(os.path.join(root, filename))
except OSError: # File not found or insufficient rights.
continue
except configparser.Error: # Invalid file format.
continue
if "metadata" in parser and "hidden" in parser["metadata"] and parser["metadata"]["hidden"] == "True":
stack_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0])
hidden_global_stacks.add(stack_id)
# The user container and definition changes container are specific to this stack. We need to delete those too.
if "containers" in parser:
if "0" in parser["containers"]: # User container.
hidden_instance_containers.add(parser["containers"]["0"])
if "6" in parser["containers"]: # Definition changes container.
hidden_instance_containers.add(parser["containers"]["6"])
os.remove(os.path.join(root, filename))
# Walk a second time to find all extruder stacks referring to these hidden container stacks.
for root, dirs, files in os.walk(data_storage):
dirs[:] = [dir for dir in dirs if dir not in exclude_directories]
for filename in fnmatch.filter(files, "*.extruder.cfg"):
parser = configparser.ConfigParser(interpolation = None)
try:
parser.read(os.path.join(root, filename))
except OSError: # File not found or insufficient rights.
continue
except configparser.Error: # Invalid file format.
continue
if "metadata" in parser and "machine" in parser["metadata"] and parser["metadata"]["machine"] in hidden_global_stacks:
stack_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0])
hidden_extruder_stacks.add(stack_id)
# The user container and definition changes container are specific to this stack. We need to delete those too.
if "containers" in parser:
if "0" in parser["containers"]: # User container.
hidden_instance_containers.add(parser["containers"]["0"])
if "6" in parser["containers"]: # Definition changes container.
hidden_instance_containers.add(parser["containers"]["6"])
os.remove(os.path.join(root, filename))
# Walk a third time to remove all instance containers that are referred to by either of those.
for root, dirs, files in os.walk(data_storage):
dirs[:] = [dir for dir in dirs if dir not in exclude_directories]
for filename in fnmatch.filter(files, "*.inst.cfg"):
container_id = urllib.parse.unquote_plus(os.path.basename(filename).split(".")[0])
if container_id in hidden_instance_containers:
try:
os.remove(os.path.join(root, filename))
except OSError: # Is a directory, file not found, or insufficient rights.
continue
def getCfgVersion(self, serialised: str) -> int:
parser = configparser.ConfigParser(interpolation = None)
parser.read_string(serialised)