Task 590: .QSS File Format

Task 590: .QSS File Format

File Format Specifications for the .QSS File Format

The .QSS file format is associated with Qt Style Sheets, a text-based format used to define the visual style of Qt applications. It is analogous to CSS for HTML, allowing customization of widget appearance through selectors, properties, and values. The format is not binary but plain text, typically encoded in UTF-8. The official specifications are documented in the Qt documentation, including the syntax rules and supported elements. For detailed reference, consult the Qt Style Sheet Syntax at https://doc.qt.io/qt-6/stylesheet-syntax.html and the property reference at https://doc.qt.io/qt-6/stylesheet-reference.html.

1. List of All Properties of This File Format Intrinsic to Its File System

In the context of the .QSS file format, the properties refer to the supported style properties that can be defined within the file to customize widget appearance. These properties are intrinsic to the format's structure as a styling language. The following table lists all supported properties, along with their types and brief descriptions where applicable (based on Qt 6 documentation).

Property Name Type Description
accent-color Brush Sets the accent color for emphasizing interactive UI elements; defaults to highlight color.
alternate-background-color Brush Alternate background color for item views; defaults to palette's AlternateBase.
background Shorthand Shorthand for background-color, background-image, background-repeat, and background-position.
background-attachment Attachment Determines if background-image scrolls or is fixed in scroll areas; defaults to scroll.
background-clip Origin Rectangle to which background is clipped; defaults to border.
background-color Brush Background color of the widget.
background-image Url Background image; semi-transparent parts show background-color.
background-origin Origin Background rectangle for positioning; defaults to padding.
background-position Alignment Alignment of background image; defaults to top left.
background-repeat Repeat How background image is repeated; defaults to repeat.
border Shorthand Shorthand for border-color, border-style, and border-width.
border-bottom Shorthand Shorthand for bottom border.
border-bottom-color Brush Color of bottom border edge.
border-bottom-left-radius Radius Radius of bottom-left border corner.
border-bottom-right-radius Radius Radius of bottom-right border corner.
border-bottom-style Style Style of bottom border edge.
border-bottom-width Length Width of bottom border edge.
border-color Brush Color of all border edges; defaults to color property.
border-image Image Image for border, sliced into nine parts.
border-left Shorthand Shorthand for left border.
border-left-color Brush Color of left border edge.
border-left-style Style Style of left border edge.
border-left-width Length Width of left border edge.
border-radius Radius Radius of all border corners.
border-right Shorthand Shorthand for right border.
border-right-color Brush Color of right border edge.
border-right-style Style Style of right border edge.
border-right-width Length Width of right border edge.
border-style Style Style of all border edges; defaults to none.
border-top Shorthand Shorthand for top border.
border-top-color Brush Color of top border edge.
border-top-left-radius Radius Radius of top-left border corner.
border-top-right-radius Radius Radius of top-right border corner.
border-top-style Style Style of top border edge.
border-top-width Length Width of top border edge.
bottom Length Offset for subcontrol positioning.
button-layout Number Layout of buttons in dialog boxes; defaults to style hint.
color Brush Text color; defaults to palette foreground.
dialogbuttonbox-buttons-have-icons Boolean Whether dialog buttons show icons.
font Shorthand Shorthand for font-family, font-size, font-style, font-weight.
font-family String Font family name.
font-size Size Font size.
font-style Style Font style (e.g., normal, italic).
font-weight Weight Font weight.
gridline-color Color Color of grid lines in item views.
height Length Height of widget or subcontrol.
image Url Image for subcontrols like indicators.
image-position Alignment Position of subcontrol image.
left Length Offset for subcontrol positioning.
lineedit-password-character Number Unicode character for password masking.
lineedit-password-mask-delay Number Delay before masking password characters.
margin Box Shorthand for margins.
margin-bottom Length Bottom margin.
margin-left Length Left margin.
margin-right Length Right margin.
margin-top Length Top margin.
max-height Length Maximum height.
max-width Length Maximum width.
messagebox-text-interaction-flags Flags Interaction flags for message box text.
min-height Length Minimum height.
min-width Length Minimum width.
opacity Number Widget opacity (0.0 to 1.0).
outline Shorthand Shorthand for outline-color, outline-style.
outline-color Color Outline color.
outline-offset Length Outline offset.
outline-radius Radius Outline corner radius.
outline-bottom-left-radius Radius Bottom-left outline radius.
outline-bottom-right-radius Radius Bottom-right outline radius.
outline-style Style Outline style.
outline-top-left-radius Radius Top-left outline radius.
outline-top-right-radius Radius Top-right outline radius.
padding Box Shorthand for padding.
padding-bottom Length Bottom padding.
padding-left Length Left padding.
padding-right Length Right padding.
padding-top Length Top padding.
paint-alternating-row-colors-for-empty-area Boolean Whether to paint alternating colors for empty areas in item views.
position Position Positioning mode for subcontrols (relative or absolute).
selection-background-color Brush Background color for selected text/items.
selection-color Brush Foreground color for selected text/items.
show-decoration-selected Boolean Whether selection decorates full row in item views.
spacing Length Spacing between subcontrols or items.
subcontrol-origin Origin Origin rectangle for subcontrol positioning.
subcontrol-position Alignment Position of subcontrol.
text-align Alignment Text alignment.
text-decoration Decoration Text decoration (e.g., underline).
titletext-align Alignment Alignment of title text in group boxes.
top Length Offset for subcontrol positioning.
width Length Width of widget or subcontrol.

3. Ghost Blog Embedded HTML JavaScript for Drag and Drop .QSS File

The following is a complete HTML document with embedded JavaScript that allows a user to drag and drop a .QSS file. It validates the file extension, reads the content, parses the properties (extracting property names from the style declarations using a regular expression), and displays them on the screen. Only properties matching the list above are displayed if found.

QSS Property Dumper
Drag and drop a .QSS file here

4. Python Class for .QSS File Handling

The following Python class can open a .QSS file, parse (decode) its content to extract supported properties and their values, print them to the console, and write a new .QSS file with specified properties.

import re
import os

class QSSHandler:
    def __init__(self):
        self.supported_properties = {
            'accent-color', 'alternate-background-color', 'background', 'background-attachment', 'background-clip',
            'background-color', 'background-image', 'background-origin', 'background-position', 'background-repeat',
            'border', 'border-bottom', 'border-bottom-color', 'border-bottom-left-radius', 'border-bottom-right-radius',
            'border-bottom-style', 'border-bottom-width', 'border-color', 'border-image', 'border-left', 'border-left-color',
            'border-left-style', 'border-left-width', 'border-radius', 'border-right', 'border-right-color', 'border-right-style',
            'border-right-width', 'border-style', 'border-top', 'border-top-color', 'border-top-left-radius', 'border-top-right-radius',
            'border-top-style', 'border-top-width', 'bottom', 'button-layout', 'color', 'dialogbuttonbox-buttons-have-icons',
            'font', 'font-family', 'font-size', 'font-style', 'font-weight', 'gridline-color', 'height', 'image', 'image-position',
            'left', 'lineedit-password-character', 'lineedit-password-mask-delay', 'margin', 'margin-bottom', 'margin-left',
            'margin-right', 'margin-top', 'max-height', 'max-width', 'messagebox-text-interaction-flags', 'min-height', 'min-width',
            'opacity', 'outline', 'outline-color', 'outline-offset', 'outline-radius', 'outline-bottom-left-radius',
            'outline-bottom-right-radius', 'outline-style', 'outline-top-left-radius', 'outline-top-right-radius', 'padding',
            'padding-bottom', 'padding-left', 'padding-right', 'padding-top', 'paint-alternating-row-colors-for-empty-area',
            'position', 'selection-background-color', 'selection-color', 'show-decoration-selected', 'spacing', 'subcontrol-origin',
            'subcontrol-position', 'text-align', 'text-decoration', 'titletext-align', 'top', 'width'
        }
        self.properties = {}

    def open_and_decode(self, filepath):
        if not filepath.endswith('.qss'):
            raise ValueError("File must have .qss extension.")
        if not os.path.exists(filepath):
            raise FileNotFoundError("File not found.")
        with open(filepath, 'r', encoding='utf-8') as f:
            content = f.read()
        regex = r'([\w-]+)\s*:\s*([^;]+);'
        matches = re.findall(regex, content)
        self.properties = {prop: value for prop, value in matches if prop in self.supported_properties}

    def print_properties(self):
        for prop, value in self.properties.items():
            print(f"{prop}: {value}")

    def write(self, filepath, selector='*', new_properties=None):
        if new_properties:
            self.properties.update({k: v for k, v in new_properties.items() if k in self.supported_properties})
        with open(filepath, 'w', encoding='utf-8') as f:
            f.write(f"{selector} {{\n")
            for prop, value in self.properties.items():
                f.write(f"    {prop}: {value};\n")
            f.write("}\n")

5. Java Class for .QSS File Handling

The following Java class can open a .QSS file, parse its content to extract supported properties and their values, print them to the console, and write a new .QSS file with specified properties.

import java.io.*;
import java.util.*;
import java.util.regex.*;

public class QSSHandler {
    private Set<String> supportedProperties = new HashSet<>(Arrays.asList(
        "accent-color", "alternate-background-color", "background", "background-attachment", "background-clip",
        "background-color", "background-image", "background-origin", "background-position", "background-repeat",
        "border", "border-bottom", "border-bottom-color", "border-bottom-left-radius", "border-bottom-right-radius",
        "border-bottom-style", "border-bottom-width", "border-color", "border-image", "border-left", "border-left-color",
        "border-left-style", "border-left-width", "border-radius", "border-right", "border-right-color", "border-right-style",
        "border-right-width", "border-style", "border-top", "border-top-color", "border-top-left-radius", "border-top-right-radius",
        "border-top-style", "border-top-width", "bottom", "button-layout", "color", "dialogbuttonbox-buttons-have-icons",
        "font", "font-family", "font-size", "font-style", "font-weight", "gridline-color", "height", "image", "image-position",
        "left", "lineedit-password-character", "lineedit-password-mask-delay", "margin", "margin-bottom", "margin-left",
        "margin-right", "margin-top", "max-height", "max-width", "messagebox-text-interaction-flags", "min-height", "min-width",
        "opacity", "outline", "outline-color", "outline-offset", "outline-radius", "outline-bottom-left-radius",
        "outline-bottom-right-radius", "outline-style", "outline-top-left-radius", "outline-top-right-radius", "padding",
        "padding-bottom", "padding-left", "padding-right", "padding-top", "paint-alternating-row-colors-for-empty-area",
        "position", "selection-background-color", "selection-color", "show-decoration-selected", "spacing", "subcontrol-origin",
        "subcontrol-position", "text-align", "text-decoration", "titletext-align", "top", "width"
    ));
    private Map<String, String> properties = new HashMap<>();

    public void openAndDecode(String filepath) throws IOException {
        if (!filepath.endsWith(".qss")) {
            throw new IllegalArgumentException("File must have .qss extension.");
        }
        File file = new File(filepath);
        if (!file.exists()) {
            throw new FileNotFoundException("File not found.");
        }
        StringBuilder content = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line).append("\n");
            }
        }
        Pattern pattern = Pattern.compile("([\\w-]+)\\s*:\\s*([^;]+);");
        Matcher matcher = pattern.matcher(content.toString());
        while (matcher.find()) {
            String prop = matcher.group(1).trim();
            if (supportedProperties.contains(prop)) {
                properties.put(prop, matcher.group(2).trim());
            }
        }
    }

    public void printProperties() {
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }

    public void write(String filepath, String selector, Map<String, String> newProperties) throws IOException {
        if (newProperties != null) {
            newProperties.forEach((k, v) -> {
                if (supportedProperties.contains(k)) {
                    properties.put(k, v);
                }
            });
        }
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filepath))) {
            writer.write(selector + " {\n");
            for (Map.Entry<String, String> entry : properties.entrySet()) {
                writer.write("    " + entry.getKey() + ": " + entry.getValue() + ";\n");
            }
            writer.write("}\n");
        }
    }
}

6. JavaScript Class for .QSS File Handling

The following JavaScript class (Node.js compatible) can open a .QSS file, parse its content to extract supported properties and their values, print them to the console, and write a new .QSS file with specified properties.

const fs = require('fs');

class QSSHandler {
    constructor() {
        this.supportedProperties = new Set([
            'accent-color', 'alternate-background-color', 'background', 'background-attachment', 'background-clip',
            'background-color', 'background-image', 'background-origin', 'background-position', 'background-repeat',
            'border', 'border-bottom', 'border-bottom-color', 'border-bottom-left-radius', 'border-bottom-right-radius',
            'border-bottom-style', 'border-bottom-width', 'border-color', 'border-image', 'border-left', 'border-left-color',
            'border-left-style', 'border-left-width', 'border-radius', 'border-right', 'border-right-color', 'border-right-style',
            'border-right-width', 'border-style', 'border-top', 'border-top-color', 'border-top-left-radius', 'border-top-right-radius',
            'border-top-style', 'border-top-width', 'bottom', 'button-layout', 'color', 'dialogbuttonbox-buttons-have-icons',
            'font', 'font-family', 'font-size', 'font-style', 'font-weight', 'gridline-color', 'height', 'image', 'image-position',
            'left', 'lineedit-password-character', 'lineedit-password-mask-delay', 'margin', 'margin-bottom', 'margin-left',
            'margin-right', 'margin-top', 'max-height', 'max-width', 'messagebox-text-interaction-flags', 'min-height', 'min-width',
            'opacity', 'outline', 'outline-color', 'outline-offset', 'outline-radius', 'outline-bottom-left-radius',
            'outline-bottom-right-radius', 'outline-style', 'outline-top-left-radius', 'outline-top-right-radius', 'padding',
            'padding-bottom', 'padding-left', 'padding-right', 'padding-top', 'paint-alternating-row-colors-for-empty-area',
            'position', 'selection-background-color', 'selection-color', 'show-decoration-selected', 'spacing', 'subcontrol-origin',
            'subcontrol-position', 'text-align', 'text-decoration', 'titletext-align', 'top', 'width'
        ]);
        this.properties = new Map();
    }

    openAndDecode(filepath) {
        if (!filepath.endsWith('.qss')) {
            throw new Error('File must have .qss extension.');
        }
        if (!fs.existsSync(filepath)) {
            throw new Error('File not found.');
        }
        const content = fs.readFileSync(filepath, 'utf-8');
        const regex = /([\w-]+)\s*:\s*([^;]+);/g;
        let match;
        while ((match = regex.exec(content)) !== null) {
            const prop = match[1].trim();
            if (this.supportedProperties.has(prop)) {
                this.properties.set(prop, match[2].trim());
            }
        }
    }

    printProperties() {
        for (const [prop, value] of this.properties) {
            console.log(`${prop}: ${value}`);
        }
    }

    write(filepath, selector = '*', newProperties = {}) {
        for (const [k, v] of Object.entries(newProperties)) {
            if (this.supportedProperties.has(k)) {
                this.properties.set(k, v);
            }
        }
        let output = `${selector} {\n`;
        for (const [prop, value] of this.properties) {
            output += `    ${prop}: ${value};\n`;
        }
        output += '}\n';
        fs.writeFileSync(filepath, output, 'utf-8');
    }
}

7. C++ Class for .QSS File Handling

The following C++ class can open a .QSS file, parse its content to extract supported properties and their values, print them to the console, and write a new .QSS file with specified properties. (Note: Requires <regex> support; compile with C++11 or later.)

#include <iostream>
#include <fstream>
#include <string>
#include <regex>
#include <unordered_set>
#include <unordered_map>

class QSSHandler {
private:
    std::unordered_set<std::string> supported_properties = {
        "accent-color", "alternate-background-color", "background", "background-attachment", "background-clip",
        "background-color", "background-image", "background-origin", "background-position", "background-repeat",
        "border", "border-bottom", "border-bottom-color", "border-bottom-left-radius", "border-bottom-right-radius",
        "border-bottom-style", "border-bottom-width", "border-color", "border-image", "border-left", "border-left-color",
        "border-left-style", "border-left-width", "border-radius", "border-right", "border-right-color", "border-right-style",
        "border-right-width", "border-style", "border-top", "border-top-color", "border-top-left-radius", "border-top-right-radius",
        "border-top-style", "border-top-width", "bottom", "button-layout", "color", "dialogbuttonbox-buttons-have-icons",
        "font", "font-family", "font-size", "font-style", "font-weight", "gridline-color", "height", "image", "image-position",
        "left", "lineedit-password-character", "lineedit-password-mask-delay", "margin", "margin-bottom", "margin-left",
        "margin-right", "margin-top", "max-height", "max-width", "messagebox-text-interaction-flags", "min-height", "min-width",
        "opacity", "outline", "outline-color", "outline-offset", "outline-radius", "outline-bottom-left-radius",
        "outline-bottom-right-radius", "outline-style", "outline-top-left-radius", "outline-top-right-radius", "padding",
        "padding-bottom", "padding-left", "padding-right", "padding-top", "paint-alternating-row-colors-for-empty-area",
        "position", "selection-background-color", "selection-color", "show-decoration-selected", "spacing", "subcontrol-origin",
        "subcontrol-position", "text-align", "text-decoration", "titletext-align", "top", "width"
    };
    std::unordered_map<std::string, std::string> properties;

public:
    void openAndDecode(const std::string& filepath) {
        if (filepath.substr(filepath.find_last_of(".") + 1) != "qss") {
            throw std::invalid_argument("File must have .qss extension.");
        }
        std::ifstream file(filepath);
        if (!file.is_open()) {
            throw std::runtime_error("File not found.");
        }
        std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
        file.close();
        std::regex regex(R"(([\w-]+)\s*:\s*([^;]+);)");
        std::sregex_iterator iter(content.begin(), content.end(), regex);
        std::sregex_iterator end;
        for (; iter != end; ++iter) {
            std::string prop = iter->str(1);
            if (supported_properties.count(prop)) {
                properties[prop] = iter->str(2);
            }
        }
    }

    void printProperties() const {
        for (const auto& pair : properties) {
            std::cout << pair.first << ": " << pair.second << std::endl;
        }
    }

    void write(const std::string& filepath, const std::string& selector = "*", const std::unordered_map<std::string, std::string>& new_properties = {}) {
        for (const auto& pair : new_properties) {
            if (supported_properties.count(pair.first)) {
                properties[pair.first] = pair.second;
            }
        }
        std::ofstream file(filepath);
        if (!file.is_open()) {
            throw std::runtime_error("Unable to write file.");
        }
        file << selector << " {\n";
        for (const auto& pair : properties) {
            file << "    " << pair.first << ": " << pair.second << ";\n";
        }
        file << "}\n";
        file.close();
    }
};