mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
- Add printers - Delete printers - Use polkit APIs as fallback on auth errors - Fix ref system to conditionally subscribe to cups when wanted
843 lines
25 KiB
QML
843 lines
25 KiB
QML
pragma Singleton
|
|
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import qs.Common
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
property int refCount: 0
|
|
|
|
onRefCountChanged: {
|
|
if (refCount > 0) {
|
|
ensureSubscription();
|
|
} else if (refCount === 0 && DMSService.activeSubscriptions.includes("cups")) {
|
|
DMSService.removeSubscription("cups");
|
|
}
|
|
}
|
|
|
|
function ensureSubscription() {
|
|
if (refCount <= 0)
|
|
return;
|
|
if (!DMSService.isConnected)
|
|
return;
|
|
if (DMSService.activeSubscriptions.includes("cups"))
|
|
return;
|
|
if (DMSService.activeSubscriptions.includes("all"))
|
|
return;
|
|
DMSService.addSubscription("cups");
|
|
if (cupsAvailable) {
|
|
getState();
|
|
}
|
|
}
|
|
|
|
property var printerNames: []
|
|
property var printers: []
|
|
property string selectedPrinter: ""
|
|
property string expandedPrinter: ""
|
|
|
|
property bool cupsAvailable: false
|
|
property bool stateInitialized: false
|
|
|
|
property var devices: []
|
|
property var ppds: []
|
|
property var printerClasses: []
|
|
|
|
readonly property var filteredDevices: {
|
|
if (!devices || devices.length === 0)
|
|
return [];
|
|
const bareProtocols = ["ipp", "ipps", "http", "https", "lpd", "socket", "beh", "dnssd", "mdns", "smb", "file", "cups-brf"];
|
|
|
|
// First pass: filter out invalid/bare protocol entries
|
|
const validDevices = devices.filter(d => {
|
|
if (!d.uri)
|
|
return false;
|
|
const uriLower = d.uri.toLowerCase();
|
|
for (let proto of bareProtocols) {
|
|
if (uriLower === proto || uriLower === proto + ":")
|
|
return false;
|
|
}
|
|
if (d.class === "network" && d.info === "Backend Error Handler")
|
|
return false;
|
|
return true;
|
|
});
|
|
|
|
// Second pass: prefer IPP over LPD for the same printer
|
|
// _printer._tcp (LPD) doesn't work well with driverless printing
|
|
// _ipp._tcp or _ipps._tcp (IPP) should be preferred
|
|
const ippDeviceHosts = new Set();
|
|
for (const d of validDevices) {
|
|
if (!d.uri)
|
|
continue;
|
|
// Extract hostname from dnssd URIs like dnssd://Name%20[mac]._ipp._tcp.local
|
|
const ippMatch = d.uri.match(/dnssd:\/\/[^/]*\._ipps?\._tcp/);
|
|
if (ippMatch) {
|
|
// Extract the unique identifier (usually MAC address in brackets)
|
|
const macMatch = d.uri.match(/\[([a-f0-9]+)\]/i);
|
|
if (macMatch)
|
|
ippDeviceHosts.add(macMatch[1].toLowerCase());
|
|
}
|
|
}
|
|
|
|
// Filter out _printer._tcp devices when we have _ipp._tcp for the same printer
|
|
return validDevices.filter(d => {
|
|
if (!d.uri)
|
|
return true;
|
|
// If this is an LPD device, check if we have an IPP alternative
|
|
if (d.uri.includes("._printer._tcp")) {
|
|
const macMatch = d.uri.match(/\[([a-f0-9]+)\]/i);
|
|
if (macMatch && ippDeviceHosts.has(macMatch[1].toLowerCase())) {
|
|
return false; // Skip LPD device, we have IPP
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
function decodeUri(str) {
|
|
if (!str)
|
|
return "";
|
|
try {
|
|
return decodeURIComponent(str.replace(/\+/g, " "));
|
|
} catch (e) {
|
|
return str;
|
|
}
|
|
}
|
|
|
|
function getDeviceDisplayName(device) {
|
|
if (!device)
|
|
return "";
|
|
if (device.info && device.info.length > 0) {
|
|
return decodeUri(device.info);
|
|
}
|
|
if (device.makeModel && device.makeModel.length > 0) {
|
|
return decodeUri(device.makeModel);
|
|
}
|
|
return decodeUri(device.uri);
|
|
}
|
|
|
|
function getDeviceSubtitle(device) {
|
|
if (!device)
|
|
return "";
|
|
const parts = [];
|
|
if (device.class) {
|
|
switch (device.class) {
|
|
case "direct":
|
|
parts.push(I18n.tr("Local"));
|
|
break;
|
|
case "network":
|
|
parts.push(I18n.tr("Network"));
|
|
break;
|
|
case "file":
|
|
parts.push(I18n.tr("File"));
|
|
break;
|
|
default:
|
|
parts.push(device.class);
|
|
}
|
|
}
|
|
if (device.location)
|
|
parts.push(decodeUri(device.location));
|
|
return parts.join(" • ");
|
|
}
|
|
|
|
function suggestPrinterName(device) {
|
|
if (!device)
|
|
return "";
|
|
let name = device.info || device.makeModel || "";
|
|
name = name.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
return name.substring(0, 32) || "Printer";
|
|
}
|
|
|
|
function getMatchingPPDs(device) {
|
|
if (!device || !ppds || ppds.length === 0)
|
|
return [];
|
|
const isDnssd = device.uri && (device.uri.startsWith("dnssd://") || device.uri.startsWith("ipp://") || device.uri.startsWith("ipps://"));
|
|
if (isDnssd) {
|
|
const driverless = ppds.filter(p => p.name === "driverless" || p.name === "everywhere" || (p.makeModel && p.makeModel.toLowerCase().includes("driverless")));
|
|
if (driverless.length > 0)
|
|
return driverless;
|
|
}
|
|
if (!device.makeModel)
|
|
return [];
|
|
const makeModelLower = device.makeModel.toLowerCase();
|
|
const words = makeModelLower.split(/[\s_-]+/).filter(w => w.length > 2);
|
|
return ppds.filter(p => {
|
|
if (!p.makeModel)
|
|
return false;
|
|
const ppdLower = p.makeModel.toLowerCase();
|
|
return words.some(w => ppdLower.includes(w));
|
|
}).slice(0, 10);
|
|
}
|
|
|
|
property bool loadingDevices: false
|
|
property bool loadingPPDs: false
|
|
property bool loadingClasses: false
|
|
property bool creatingPrinter: false
|
|
|
|
signal cupsStateUpdate
|
|
|
|
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
|
|
|
|
Component.onCompleted: {
|
|
if (socketPath && socketPath.length > 0) {
|
|
checkDMSCapabilities();
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: DMSService
|
|
|
|
function onConnectionStateChanged() {
|
|
if (DMSService.isConnected) {
|
|
checkDMSCapabilities();
|
|
ensureSubscription();
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: DMSService
|
|
enabled: DMSService.isConnected
|
|
|
|
function onCupsStateUpdate(data) {
|
|
console.log("CupsService: Subscription update received");
|
|
getState();
|
|
}
|
|
|
|
function onCapabilitiesChanged() {
|
|
checkDMSCapabilities();
|
|
}
|
|
}
|
|
|
|
function checkDMSCapabilities() {
|
|
if (!DMSService.isConnected)
|
|
return;
|
|
if (DMSService.capabilities.length === 0)
|
|
return;
|
|
cupsAvailable = DMSService.capabilities.includes("cups");
|
|
|
|
if (cupsAvailable && !stateInitialized) {
|
|
stateInitialized = true;
|
|
getState();
|
|
}
|
|
}
|
|
|
|
function getState() {
|
|
if (!cupsAvailable)
|
|
return;
|
|
DMSService.sendRequest("cups.getPrinters", null, response => {
|
|
if (response.result) {
|
|
updatePrinters(response.result);
|
|
fetchAllJobs();
|
|
}
|
|
});
|
|
}
|
|
|
|
function updatePrinters(printersData) {
|
|
printerNames = printersData.map(p => p.name);
|
|
|
|
let printersObj = {};
|
|
for (var i = 0; i < printersData.length; i++) {
|
|
let printer = printersData[i];
|
|
printersObj[printer.name] = {
|
|
"name": printer.name,
|
|
"uri": printer.uri || "",
|
|
"state": printer.state,
|
|
"stateReason": printer.stateReason,
|
|
"location": printer.location || "",
|
|
"info": printer.info || "",
|
|
"makeModel": printer.makeModel || "",
|
|
"accepting": printer.accepting !== false,
|
|
"jobs": []
|
|
};
|
|
}
|
|
printers = printersObj;
|
|
|
|
if (printerNames.length > 0) {
|
|
if (selectedPrinter.length > 0) {
|
|
if (!printerNames.includes(selectedPrinter)) {
|
|
selectedPrinter = printerNames[0];
|
|
}
|
|
} else {
|
|
selectedPrinter = printerNames[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
function fetchAllJobs() {
|
|
for (var i = 0; i < printerNames.length; i++) {
|
|
fetchJobsForPrinter(printerNames[i]);
|
|
}
|
|
}
|
|
|
|
function fetchJobsForPrinter(printerName) {
|
|
const params = {
|
|
"printerName": printerName
|
|
};
|
|
|
|
DMSService.sendRequest("cups.getJobs", params, response => {
|
|
if (response.result && printers[printerName]) {
|
|
let updatedPrinters = Object.assign({}, printers);
|
|
updatedPrinters[printerName].jobs = response.result;
|
|
printers = updatedPrinters;
|
|
}
|
|
});
|
|
}
|
|
|
|
function getSelectedPrinter() {
|
|
return selectedPrinter;
|
|
}
|
|
|
|
function setSelectedPrinter(printerName) {
|
|
if (printerNames.length > 0) {
|
|
if (printerNames.includes(printerName)) {
|
|
selectedPrinter = printerName;
|
|
} else {
|
|
selectedPrinter = printerNames[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
function getPrintersNum() {
|
|
if (!cupsAvailable)
|
|
return 0;
|
|
|
|
return printerNames.length;
|
|
}
|
|
|
|
function getPrintersNames() {
|
|
if (!cupsAvailable)
|
|
return [];
|
|
|
|
return printerNames;
|
|
}
|
|
|
|
function getTotalJobsNum() {
|
|
if (!cupsAvailable)
|
|
return 0;
|
|
|
|
var result = 0;
|
|
for (var i = 0; i < printerNames.length; i++) {
|
|
var printerName = printerNames[i];
|
|
if (printers[printerName] && printers[printerName].jobs) {
|
|
result += printers[printerName].jobs.length;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function getCurrentPrinterState() {
|
|
if (!cupsAvailable || !selectedPrinter)
|
|
return "";
|
|
|
|
var printer = printers[selectedPrinter];
|
|
return printer.state;
|
|
}
|
|
|
|
function getCurrentPrinterStatePrettyShort() {
|
|
if (!cupsAvailable || !selectedPrinter)
|
|
return "";
|
|
|
|
var printer = printers[selectedPrinter];
|
|
return getPrinterStateTranslation(printer.state) + " (" + getPrinterStateReasonTranslation(printer.stateReason) + ")";
|
|
}
|
|
|
|
function getCurrentPrinterStatePretty() {
|
|
if (!cupsAvailable || !selectedPrinter)
|
|
return "";
|
|
|
|
var printer = printers[selectedPrinter];
|
|
return getPrinterStateTranslation(printer.state) + " (" + I18n.tr("Reason") + ": " + getPrinterStateReasonTranslation(printer.stateReason) + ")";
|
|
}
|
|
|
|
function getCurrentPrinterJobs() {
|
|
if (!cupsAvailable || !selectedPrinter)
|
|
return [];
|
|
|
|
return getJobs(selectedPrinter);
|
|
}
|
|
|
|
function getJobs(printerName) {
|
|
if (!cupsAvailable)
|
|
return "";
|
|
|
|
var printer = printers[printerName];
|
|
return printer.jobs;
|
|
}
|
|
|
|
function getJobsNum(printerName) {
|
|
if (!cupsAvailable)
|
|
return 0;
|
|
|
|
var printer = printers[printerName];
|
|
return printer.jobs.length;
|
|
}
|
|
|
|
function pausePrinter(printerName) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName
|
|
};
|
|
|
|
DMSService.sendRequest("cups.pausePrinter", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to pause printer") + " - " + response.error);
|
|
} else {
|
|
getState();
|
|
}
|
|
});
|
|
}
|
|
|
|
function resumePrinter(printerName) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName
|
|
};
|
|
|
|
DMSService.sendRequest("cups.resumePrinter", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to resume printer") + " - " + response.error);
|
|
} else {
|
|
getState();
|
|
}
|
|
});
|
|
}
|
|
|
|
function cancelJob(printerName, jobID) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName,
|
|
"jobID": jobID
|
|
};
|
|
|
|
DMSService.sendRequest("cups.cancelJob", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to cancel selected job") + " - " + response.error);
|
|
} else {
|
|
fetchJobsForPrinter(printerName);
|
|
}
|
|
});
|
|
}
|
|
|
|
function purgeJobs(printerName) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName
|
|
};
|
|
|
|
DMSService.sendRequest("cups.purgeJobs", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to cancel all jobs") + " - " + response.error);
|
|
} else {
|
|
fetchJobsForPrinter(printerName);
|
|
}
|
|
});
|
|
}
|
|
|
|
function getDevices() {
|
|
if (!cupsAvailable)
|
|
return;
|
|
loadingDevices = true;
|
|
DMSService.sendRequest("cups.getDevices", null, response => {
|
|
loadingDevices = false;
|
|
if (response.result) {
|
|
devices = response.result;
|
|
}
|
|
});
|
|
}
|
|
|
|
function getPPDs() {
|
|
if (!cupsAvailable)
|
|
return;
|
|
loadingPPDs = true;
|
|
DMSService.sendRequest("cups.getPPDs", null, response => {
|
|
loadingPPDs = false;
|
|
if (response.result) {
|
|
ppds = response.result;
|
|
}
|
|
});
|
|
}
|
|
|
|
function getClasses() {
|
|
if (!cupsAvailable)
|
|
return;
|
|
loadingClasses = true;
|
|
DMSService.sendRequest("cups.getClasses", null, response => {
|
|
loadingClasses = false;
|
|
if (response.result) {
|
|
printerClasses = response.result;
|
|
}
|
|
});
|
|
}
|
|
|
|
function createPrinter(name, deviceURI, ppd, options) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
creatingPrinter = true;
|
|
const params = {
|
|
"name": name,
|
|
"deviceURI": deviceURI,
|
|
"ppd": ppd
|
|
};
|
|
if (options) {
|
|
if (options.shared !== undefined)
|
|
params.shared = options.shared;
|
|
if (options.location)
|
|
params.location = options.location;
|
|
if (options.information)
|
|
params.information = options.information;
|
|
if (options.errorPolicy)
|
|
params.errorPolicy = options.errorPolicy;
|
|
}
|
|
|
|
DMSService.sendRequest("cups.createPrinter", params, response => {
|
|
creatingPrinter = false;
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to create printer") + " - " + response.error);
|
|
} else {
|
|
ToastService.showInfo(I18n.tr("Printer created successfully"));
|
|
getState();
|
|
}
|
|
});
|
|
}
|
|
|
|
function deletePrinter(printerName) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName
|
|
};
|
|
|
|
DMSService.sendRequest("cups.deletePrinter", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to delete printer") + " - " + response.error);
|
|
} else {
|
|
ToastService.showInfo(I18n.tr("Printer deleted"));
|
|
if (selectedPrinter === printerName) {
|
|
selectedPrinter = "";
|
|
}
|
|
getState();
|
|
}
|
|
});
|
|
}
|
|
|
|
function acceptJobs(printerName) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName
|
|
};
|
|
|
|
DMSService.sendRequest("cups.acceptJobs", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to enable job acceptance") + " - " + response.error);
|
|
} else {
|
|
getState();
|
|
}
|
|
});
|
|
}
|
|
|
|
function rejectJobs(printerName) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName
|
|
};
|
|
|
|
DMSService.sendRequest("cups.rejectJobs", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to disable job acceptance") + " - " + response.error);
|
|
} else {
|
|
getState();
|
|
}
|
|
});
|
|
}
|
|
|
|
function setPrinterShared(printerName, shared) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName,
|
|
"shared": shared
|
|
};
|
|
|
|
DMSService.sendRequest("cups.setPrinterShared", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to update sharing") + " - " + response.error);
|
|
} else {
|
|
getState();
|
|
}
|
|
});
|
|
}
|
|
|
|
function setPrinterLocation(printerName, location) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName,
|
|
"location": location
|
|
};
|
|
|
|
DMSService.sendRequest("cups.setPrinterLocation", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to update location") + " - " + response.error);
|
|
} else {
|
|
getState();
|
|
}
|
|
});
|
|
}
|
|
|
|
function setPrinterInfo(printerName, info) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName,
|
|
"info": info
|
|
};
|
|
|
|
DMSService.sendRequest("cups.setPrinterInfo", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to update description") + " - " + response.error);
|
|
} else {
|
|
getState();
|
|
}
|
|
});
|
|
}
|
|
|
|
function printTestPage(printerName) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"printerName": printerName
|
|
};
|
|
|
|
DMSService.sendRequest("cups.printTestPage", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to print test page") + " - " + response.error);
|
|
} else {
|
|
ToastService.showInfo(I18n.tr("Test page sent to printer"));
|
|
fetchJobsForPrinter(printerName);
|
|
}
|
|
});
|
|
}
|
|
|
|
function moveJob(jobID, destPrinter) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"jobID": jobID,
|
|
"destPrinter": destPrinter
|
|
};
|
|
|
|
DMSService.sendRequest("cups.moveJob", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to move job") + " - " + response.error);
|
|
} else {
|
|
fetchAllJobs();
|
|
}
|
|
});
|
|
}
|
|
|
|
function restartJob(jobID) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"jobID": jobID
|
|
};
|
|
|
|
DMSService.sendRequest("cups.restartJob", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to restart job") + " - " + response.error);
|
|
} else {
|
|
fetchAllJobs();
|
|
}
|
|
});
|
|
}
|
|
|
|
function holdJob(jobID, holdUntil) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"jobID": jobID
|
|
};
|
|
if (holdUntil) {
|
|
params.holdUntil = holdUntil;
|
|
}
|
|
|
|
DMSService.sendRequest("cups.holdJob", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to hold job") + " - " + response.error);
|
|
} else {
|
|
fetchAllJobs();
|
|
}
|
|
});
|
|
}
|
|
|
|
function addPrinterToClass(className, printerName) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"className": className,
|
|
"printerName": printerName
|
|
};
|
|
|
|
DMSService.sendRequest("cups.addPrinterToClass", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to add printer to class") + " - " + response.error);
|
|
} else {
|
|
getClasses();
|
|
}
|
|
});
|
|
}
|
|
|
|
function removePrinterFromClass(className, printerName) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"className": className,
|
|
"printerName": printerName
|
|
};
|
|
|
|
DMSService.sendRequest("cups.removePrinterFromClass", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to remove printer from class") + " - " + response.error);
|
|
} else {
|
|
getClasses();
|
|
}
|
|
});
|
|
}
|
|
|
|
function deleteClass(className) {
|
|
if (!cupsAvailable)
|
|
return;
|
|
const params = {
|
|
"className": className
|
|
};
|
|
|
|
DMSService.sendRequest("cups.deleteClass", params, response => {
|
|
if (response.error) {
|
|
ToastService.showError(I18n.tr("Failed to delete class") + " - " + response.error);
|
|
} else {
|
|
getClasses();
|
|
}
|
|
});
|
|
}
|
|
|
|
function getPrinterData(printerName) {
|
|
if (!printers || !printers[printerName])
|
|
return null;
|
|
return printers[printerName];
|
|
}
|
|
|
|
function getJobStateTranslation(state) {
|
|
switch (state) {
|
|
case "pending":
|
|
return I18n.tr("Pending");
|
|
case "pending-held":
|
|
return I18n.tr("Held");
|
|
case "processing":
|
|
return I18n.tr("Processing");
|
|
case "processing-stopped":
|
|
return I18n.tr("Stopped");
|
|
case "canceled":
|
|
return I18n.tr("Canceled");
|
|
case "aborted":
|
|
return I18n.tr("Aborted");
|
|
case "completed":
|
|
return I18n.tr("Completed");
|
|
default:
|
|
return state;
|
|
}
|
|
}
|
|
|
|
readonly property var states: ({
|
|
"idle": I18n.tr("Idle"),
|
|
"processing": I18n.tr("Processing"),
|
|
"stopped": I18n.tr("Stopped")
|
|
})
|
|
|
|
readonly property var reasonsGeneral: ({
|
|
"none": I18n.tr("None"),
|
|
"other": I18n.tr("Other")
|
|
})
|
|
|
|
readonly property var reasonsSupplies: ({
|
|
"toner-low": I18n.tr("Toner Low"),
|
|
"toner-empty": I18n.tr("Toner Empty"),
|
|
"marker-supply-low": I18n.tr("Marker Supply Low"),
|
|
"marker-supply-empty": I18n.tr("Marker Supply Empty"),
|
|
"marker-waste-almost-full": I18n.tr("Marker Waste Almost Full"),
|
|
"marker-waste-full": I18n.tr("Marker Waste Full")
|
|
})
|
|
|
|
readonly property var reasonsMedia: ({
|
|
"media-low": I18n.tr("Media Low"),
|
|
"media-empty": I18n.tr("Media Empty"),
|
|
"media-needed": I18n.tr("Media Needed"),
|
|
"media-jam": I18n.tr("Media Jam")
|
|
})
|
|
|
|
readonly property var reasonsParts: ({
|
|
"cover-open": I18n.tr("Cover Open"),
|
|
"door-open": I18n.tr("Door Open"),
|
|
"interlock-open": I18n.tr("Interlock Open"),
|
|
"output-tray-missing": I18n.tr("Output Tray Missing"),
|
|
"output-area-almost-full": I18n.tr("Output Area Almost Full"),
|
|
"output-area-full": I18n.tr("Output Area Full")
|
|
})
|
|
|
|
readonly property var reasonsErrors: ({
|
|
"paused": I18n.tr("Paused"),
|
|
"shutdown": I18n.tr("Shutdown"),
|
|
"connecting-to-device": I18n.tr("Connecting to Device"),
|
|
"timed-out": I18n.tr("Timed Out"),
|
|
"stopping": I18n.tr("Stopping"),
|
|
"stopped-partly": I18n.tr("Stopped Partly")
|
|
})
|
|
|
|
readonly property var reasonsService: ({
|
|
"spool-area-full": I18n.tr("Spool Area Full"),
|
|
"cups-missing-filter-warning": I18n.tr("CUPS Missing Filter Warning"),
|
|
"cups-insecure-filter-warning": I18n.tr("CUPS Insecure Filter Warning")
|
|
})
|
|
|
|
readonly property var reasonsConnectivity: ({
|
|
"offline-report": I18n.tr("Offline Report"),
|
|
"moving-to-paused": I18n.tr("Moving to Paused")
|
|
})
|
|
|
|
readonly property var severitySuffixes: ({
|
|
"-error": I18n.tr("Error"),
|
|
"-warning": I18n.tr("Warning"),
|
|
"-report": I18n.tr("Report")
|
|
})
|
|
|
|
function getPrinterStateTranslation(state) {
|
|
return states[state] || state;
|
|
}
|
|
|
|
function getPrinterStateReasonTranslation(reason) {
|
|
let allReasons = Object.assign({}, reasonsGeneral, reasonsSupplies, reasonsMedia, reasonsParts, reasonsErrors, reasonsService, reasonsConnectivity);
|
|
|
|
let basReason = reason;
|
|
let suffix = "";
|
|
|
|
for (let s in severitySuffixes) {
|
|
if (reason.endsWith(s)) {
|
|
basReason = reason.slice(0, -s.length);
|
|
suffix = severitySuffixes[s];
|
|
break;
|
|
}
|
|
}
|
|
|
|
let translation = allReasons[basReason] || basReason;
|
|
return suffix ? translation + " (" + suffix + ")" : translation;
|
|
}
|
|
}
|