Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package union6 for openSUSE:Factory checked 
in at 2026-10-22 15:48:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/union6 (Old)
 and      /work/SRC/openSUSE:Factory/.union6.new.2252680 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "union6"

Thu Oct 22 15:48:50 2026 rev:8 rq:1386878 version:6.8.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/union6/union6.changes    2026-10-16 
20:09:10.844872426 +0200
+++ /work/SRC/openSUSE:Factory/.union6.new.2252680/union6.changes       
2026-10-22 15:49:21.355738008 +0200
@@ -1,0 +2,23 @@
+Tue Oct 20 11:35:47 UTC 2026 - Fabian Vogt <[email protected]>
+
+- Update to 6.8.1:
+  * New bugfix release
+  * For more details see https://kde.org/announcements/plasma/6/6.8.1
+- Changes since 6.8.0:
+  * TreeViewElement: draw the branch arrow at the size of the indicator
+  * UnionStyle: underline accelerators of selectable labels only with Alt
+  * Update version for new release 6.8.1
+  * CheckBox/RadioButtonElement: Don't draw as a push button without a widget 
(kde#526764)
+  * Elements: Add validity checks
+  * :cherries: tools/styletool: Support Tar archived styles in 
install/inspect/update commands
+  * tools/styletool: Add support for extracting files from a Tar archive
+  * tools/styletool: Add support for reading existing archives to TarArchive
+  * :cherries: tools/styletool: Refactor Tar to TarArchive and make it a 
proper class
+  * ScrollAreaCornerElement: Fix validity check
+  * UnionStyle: Remove unused QSplitterHandle check
+  * CMakeLists: Remove Breeze QStyle dependency
+  * delegate: Add focusframe
+  * FocusElement: Fix validity check
+  * AbstractElement: Add changed hint on _kde_highlight_neutral
+
+-------------------------------------------------------------------

Old:
----
  union-6.8.0.tar.xz
  union-6.8.0.tar.xz.sig

New:
----
  union-6.8.1.tar.xz
  union-6.8.1.tar.xz.sig

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ union6.spec ++++++
--- /var/tmp/diff_new_pack.NIvciu/_old  2026-10-22 15:49:22.058767478 +0200
+++ /var/tmp/diff_new_pack.NIvciu/_new  2026-10-22 15:49:22.059767520 +0200
@@ -26,14 +26,14 @@
 %{!?_plasma6_version: %define _plasma6_version %(echo %{_plasma6_bugfix} | awk 
-F. '{print $1"."$2}')}
 %bcond_without released
 Name:           union6
-Version:        6.8.0
+Version:        6.8.1
 Release:        0
 Summary:        Qt style supporting both QtQuick and QtWidgets
 License:        LGPL-2.1-or-later
 URL:            https://www.kde.org/
-Source0:        %{rname}-%{version}.tar.xz
+Source0:        
https://download.kde.org/stable/plasma/%{version}/%{rname}-%{version}.tar.xz
 %if %{with released}
-Source1:        %{rname}-%{version}.tar.xz.sig
+Source1:        
https://download.kde.org/stable/plasma/%{version}/%{rname}-%{version}.tar.xz.sig
 Source2:        plasma.keyring
 %endif
 BuildRequires:  kf6-extra-cmake-modules >= %{kf6_version}


++++++ union-6.8.0.tar.xz -> union-6.8.1.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/union-6.8.0/CMakeLists.txt 
new/union-6.8.1/CMakeLists.txt
--- old/union-6.8.0/CMakeLists.txt      2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/CMakeLists.txt      2026-10-20 11:13:08.000000000 +0200
@@ -3,7 +3,7 @@
 
 cmake_minimum_required(VERSION 3.27)
 
-set(PROJECT_VERSION "6.8.0") # handled by release scripts
+set(PROJECT_VERSION "6.8.1") # handled by release scripts
 set(KF6_MIN_VERSION "6.30.0") # handled by release scripts
 set(CSS_PARSER_VERSION "1.1.0")
 
@@ -46,7 +46,6 @@
 # Options to control building outputs
 option(BUILD_OUTPUT_QTQUICK "Build the QtQuick output" ON)
 cmake_dependent_option(BUILD_OUTPUT_KIRIGAMI "Build the Kirigami output. 
Requires QtQuick output." ON "BUILD_OUTPUT_QTQUICK" OFF)
-# Builds a proxy style that uses Breeze as the base by default
 option(BUILD_OUTPUT_QTWIDGETS "Build the QtWidgets output" ON)
 
 set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of 
deprecated API excluded from the build [default=0].")
@@ -83,8 +82,6 @@
 
 if (BUILD_OUTPUT_QTWIDGETS)
     find_package(Qt6Widgets ${QT_MIN_VERSION} CONFIG REQUIRED)
-    find_package(Breeze CONFIG)
-    set_package_properties(Breeze PROPERTIES TYPE RUNTIME PURPOSE "Breeze is 
used as the QtWidgets base style by default.")
 endif()
 
 if (BUILD_OUTPUT_KIRIGAMI)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/input/css/styles/breeze/contents/css/delegate.css 
new/union-6.8.1/src/input/css/styles/breeze/contents/css/delegate.css
--- old/union-6.8.0/src/input/css/styles/breeze/contents/css/delegate.css       
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/input/css/styles/breeze/contents/css/delegate.css       
2026-10-20 11:13:08.000000000 +0200
@@ -12,6 +12,7 @@
     --delegate-spacing: var(--medium-spacing);
     --delegate-padding: var(--small-spacing);
     --delegate-total-padding: 10px; /* spacing + padding */
+    --focus-highlight-color: mix(var(--highlight-color), 
var(--view-background-color), 0.45);
 }
 
 itemdelegate,
@@ -206,6 +207,24 @@
     }
 }
 
+/* Dolphin fileitem */
+graphicsview itemviewitem {
+    &:highlighted {
+        background-color: modify-color(var(--highlight-color) set-alpha 0.75);
+        border: none;
+    }
+}
+
+focusframe {
+    background-color: transparent;
+    border: 1.25px solid var(--highlight-color);
+    border-radius: var(--corner-radius);
+    inset: 2px;
+    &:highlighted {
+        border: 1.75px solid var(--highlight-color);
+    }
+}
+
 /* For delegates with known indicators, place the indicator at the top left and
  * reduce the effective indicator size to 0. This ensures the indicator will be
  * placed inside the content item. */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/union-6.8.0/src/output/qtwidgets/UnionStyle.cpp 
new/union-6.8.1/src/output/qtwidgets/UnionStyle.cpp
--- old/union-6.8.0/src/output/qtwidgets/UnionStyle.cpp 2026-10-08 
13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/UnionStyle.cpp 2026-10-20 
11:13:08.000000000 +0200
@@ -652,8 +652,10 @@
         return false;
     case SH_ScrollBar_LeftClickAbsolutePosition:
         return true;
+    // Accelerator underlines follow the Alt key in text that is not drawn 
through drawItemText() as well, such as
+    // selectable labels.
     case SH_UnderlineShortcut:
-        return true;
+        return m_showMnemonics;
     default:
         return QCommonStyle::styleHint(hint, option, widget, returnData);
     }
@@ -776,8 +778,6 @@
         } else if (qobject_cast<const QFrame *>(currentWidget)) {
             members.prepend(ElementString::Frame);
             // Toplevels
-        } else if (qobject_cast<const QSplitterHandle *>(currentWidget)) {
-            members.prepend(ElementString::SplitterHandle);
         } else if (qobject_cast<const QAbstractSpinBox *>(currentWidget)) {
             members.prepend(ElementString::SpinBox);
         } else if (qobject_cast<const QGroupBox *>(currentWidget)) {
@@ -812,8 +812,6 @@
             members.prepend(ElementString::RubberBand);
         } else if (qobject_cast<const QSizeGrip *>(currentWidget)) {
             members.prepend(ElementString::SizeGrip);
-        } else if (qobject_cast<const QSplitterHandle *>(currentWidget)) {
-            members.prepend(ElementString::SplitterHandle);
         } else if (qobject_cast<const QStatusBar *>(currentWidget)) {
             members.prepend(ElementString::StatusBar);
         } else if (qobject_cast<const QTabBar *>(currentWidget)) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/AbstractElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/AbstractElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/AbstractElement.cpp   
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/AbstractElement.cpp   
2026-10-20 11:13:08.000000000 +0200
@@ -457,7 +457,7 @@
             elementTypes = m_style->widgetToElementHierarchy(widget);
         }
     } else {
-        elementTypes = {styleOptionToElementName(opt)};
+        elementTypes = {fallbackElementName(opt)};
     }
 
     // Meld duplicate elements that appear next to each other
@@ -477,6 +477,11 @@
     return elements;
 }
 
+QString AbstractElement::fallbackElementName(const QStyleOption *opt) const
+{
+    return styleOptionToElementName(opt);
+}
+
 Union::Properties::StylePropertyGroup *AbstractElement::queryProperties(const 
Union::ElementList &elements) const
 {
     Q_ASSERT(!elements.isEmpty());
@@ -642,14 +647,20 @@
     unionElement->setAttributes(elementAttributes());
     auto hints = elementHints();
 
-    // Window is a bit special and needs to be handled during element 
hierarchy creation,
-    // as the QStyle does not directly draw the window element.
-    if (m_widget && name == u"ApplicationWindow"_s) {
-        if (auto window = m_widget->window()) {
-            if (!window->isActiveWindow()) {
-                hints.append(u"inactive"_s);
+    if (m_widget) {
+        // Window is a bit special and needs to be handled during element 
hierarchy creation,
+        // as the QStyle does not directly draw the window element.)
+        if (name == u"ApplicationWindow"_s) {
+            if (auto window = m_widget->window()) {
+                if (!window->isActiveWindow()) {
+                    hints.append(u"inactive"_s);
+                }
             }
         }
+        // Add support for Widget KCMs showing the changed items.
+        if (m_widget->property("_kde_highlight_neutral").toBool()) {
+            hints.append(u"changed"_s);
+        }
     }
 
     unionElement->setHints(hints);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/AbstractElement.h 
new/union-6.8.1/src/output/qtwidgets/elements/AbstractElement.h
--- old/union-6.8.0/src/output/qtwidgets/elements/AbstractElement.h     
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/AbstractElement.h     
2026-10-20 11:13:08.000000000 +0200
@@ -176,6 +176,12 @@
     virtual Union::ElementList prepareElements(const QStyleOption *opt, const 
QWidget *widget, QStringList targetHierarchy = {}) const;
 
     /*!
+     * \brief The element name used by prepareElements() when there is no 
widget, such as when
+     * drawing for QtQuick. By default it is guessed from the style option 
type.
+     */
+    virtual QString fallbackElementName(const QStyleOption *opt) const;
+
+    /*!
      * \brief Queries the properties from list of elements. The properties 
match to the last element in the list,
      * inheriting anything it needs from its parents.
      */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/CheckBoxElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/CheckBoxElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/CheckBoxElement.cpp   
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/CheckBoxElement.cpp   
2026-10-20 11:13:08.000000000 +0200
@@ -140,3 +140,10 @@
     }
     return 0;
 }
+
+QString CheckBoxElement::fallbackElementName(const QStyleOption *opt) const
+{
+    Q_UNUSED(opt);
+    // QStyleOptionButton is also used by push buttons, so the option type 
would make this a Button
+    return ElementString::CheckBox;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/CheckBoxElement.h 
new/union-6.8.1/src/output/qtwidgets/elements/CheckBoxElement.h
--- old/union-6.8.0/src/output/qtwidgets/elements/CheckBoxElement.h     
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/CheckBoxElement.h     
2026-10-20 11:13:08.000000000 +0200
@@ -50,5 +50,6 @@
     void updateSubElementList() override;
     void drawIndicator(QPainter *painter) const override;
     QStringList elementHints() const override;
+    QString fallbackElementName(const QStyleOption *opt) const override;
     const QStyleOptionButton *m_buttonOption = nullptr;
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/FocusElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/FocusElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/FocusElement.cpp      
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/FocusElement.cpp      
2026-10-20 11:13:08.000000000 +0200
@@ -46,6 +46,9 @@
     m_backgroundElementList = prepareElements(m_styleOption, m_widget, 
{ElementString::FocusFrame});
     if (!m_backgroundElementList.isEmpty()) {
         m_backgroundProperties = queryProperties(m_backgroundElementList);
+        m_isValid = true;
+    } else {
+        m_isValid = false;
     }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/MenuItemElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/MenuItemElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/MenuItemElement.cpp   
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/MenuItemElement.cpp   
2026-10-20 11:13:08.000000000 +0200
@@ -144,6 +144,8 @@
         }
 
         m_isValid = true;
+    } else {
+        m_isValid = false;
     }
 
     if (!m_shortcutText.isEmpty()) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/RadioButtonElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/RadioButtonElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/RadioButtonElement.cpp        
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/RadioButtonElement.cpp        
2026-10-20 11:13:08.000000000 +0200
@@ -134,3 +134,10 @@
     }
     return 0;
 }
+
+QString RadioButtonElement::fallbackElementName(const QStyleOption *opt) const
+{
+    Q_UNUSED(opt);
+    // QStyleOptionButton is also used by push buttons, so the option type 
would make this a Button
+    return ElementString::RadioButton;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/RadioButtonElement.h 
new/union-6.8.1/src/output/qtwidgets/elements/RadioButtonElement.h
--- old/union-6.8.0/src/output/qtwidgets/elements/RadioButtonElement.h  
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/RadioButtonElement.h  
2026-10-20 11:13:08.000000000 +0200
@@ -50,5 +50,6 @@
     void updateSubElementList() override;
     void drawIndicator(QPainter *painter) const override;
     QStringList elementHints() const override;
+    QString fallbackElementName(const QStyleOption *opt) const override;
     const QStyleOptionButton *m_buttonOption = nullptr;
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/RubberBandElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/RubberBandElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/RubberBandElement.cpp 
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/RubberBandElement.cpp 
2026-10-20 11:13:08.000000000 +0200
@@ -48,5 +48,7 @@
     if (!m_backgroundElementList.isEmpty()) {
         m_backgroundProperties = queryProperties(m_backgroundElementList);
         m_isValid = true;
+    } else {
+        m_isValid = false;
     }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/ScrollAreaCornerElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/ScrollAreaCornerElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/ScrollAreaCornerElement.cpp   
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/ScrollAreaCornerElement.cpp   
2026-10-20 11:13:08.000000000 +0200
@@ -47,5 +47,8 @@
     m_backgroundElementList = prepareElements(m_cornerOption, m_widget, 
{ElementString::ScrollAreaCorner});
     if (!m_backgroundElementList.isEmpty()) {
         m_backgroundProperties = queryProperties(m_backgroundElementList);
+        m_isValid = true;
+    } else {
+        m_isValid = false;
     }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/SizeGripElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/SizeGripElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/SizeGripElement.cpp   
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/SizeGripElement.cpp   
2026-10-20 11:13:08.000000000 +0200
@@ -49,6 +49,8 @@
     if (!m_backgroundElementList.isEmpty()) {
         m_backgroundProperties = queryProperties(m_backgroundElementList);
         m_isValid = true;
+    } else {
+        m_isValid = false;
     }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/SplitterElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/SplitterElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/SplitterElement.cpp   
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/SplitterElement.cpp   
2026-10-20 11:13:08.000000000 +0200
@@ -53,6 +53,8 @@
     if (!m_backgroundElementList.isEmpty()) {
         m_backgroundProperties = queryProperties(m_backgroundElementList);
         m_isValid = true;
+    } else {
+        m_isValid = false;
     }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/TabElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/TabElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/TabElement.cpp        
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/TabElement.cpp        
2026-10-20 11:13:08.000000000 +0200
@@ -160,6 +160,8 @@
         subopt.rect = tabRect;
         m_layoutMap = layoutMap(m_backgroundElementList, &subopt, 
m_subElementList);
         m_isValid = true;
+    } else {
+        m_isValid = false;
     }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/ToolTipElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/ToolTipElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/ToolTipElement.cpp    
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/ToolTipElement.cpp    
2026-10-20 11:13:08.000000000 +0200
@@ -47,6 +47,8 @@
     if (!m_backgroundElementList.isEmpty()) {
         m_backgroundProperties = queryProperties(m_backgroundElementList);
         m_isValid = true;
+    } else {
+        m_isValid = false;
     }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/union-6.8.0/src/output/qtwidgets/elements/TreeViewElement.cpp 
new/union-6.8.1/src/output/qtwidgets/elements/TreeViewElement.cpp
--- old/union-6.8.0/src/output/qtwidgets/elements/TreeViewElement.cpp   
2026-10-08 13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/elements/TreeViewElement.cpp   
2026-10-20 11:13:08.000000000 +0200
@@ -50,6 +50,9 @@
     m_indicatorElementList = prepareElements(m_styleOption, m_widget, 
{ElementString::TreeViewDelegate, ElementString::Indicator});
     if (!m_indicatorElementList.isEmpty()) {
         m_indicatorProperties = queryProperties(m_indicatorElementList);
+        m_isValid = true;
+    } else {
+        m_isValid = false;
     }
 }
 
@@ -84,8 +87,12 @@
 
     const QPalette activePalette = m_styleOption->palette;
     const qreal dpr = painter->device() ? 
painter->device()->devicePixelRatioF() : qApp->devicePixelRatio();
-    auto iconSize = m_styleOption->rect.size();
-    const QPixmap pixmap = icon.pixmap(iconSize, dpr, enabled ? QIcon::Normal 
: QIcon::Disabled);
+    QSize iconSize = size.toSize().boundedTo(m_styleOption->rect.size());
+    if (iconSize.isEmpty()) {
+        iconSize = m_styleOption->rect.size();
+    }
+    const int side = std::min(iconSize.width(), iconSize.height());
+    const QPixmap pixmap = icon.pixmap(QSize(side, side), dpr, enabled ? 
QIcon::Normal : QIcon::Disabled);
 
     painter->save();
     auto rect = centerRect(m_styleOption->rect, size.width(), size.height());
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/union-6.8.0/src/output/qtwidgets/union.themerc 
new/union-6.8.1/src/output/qtwidgets/union.themerc
--- old/union-6.8.0/src/output/qtwidgets/union.themerc  2026-10-08 
13:28:01.000000000 +0200
+++ new/union-6.8.1/src/output/qtwidgets/union.themerc  2026-10-20 
11:13:08.000000000 +0200
@@ -21,6 +21,7 @@
 Name[nn]=Union (under utvikling)
 Name[pt_BR]=Union (Em desenvolvimento)
 Name[ro]=Union (în dezvoltare)
+Name[ru]=Union (в разработке)
 Name[sk]=Union (vo vývoji)
 Name[sl]=Union (V razvoju)
 Name[sr]=Union (у развоју)
@@ -50,6 +51,7 @@
 Comment[nn]=Ein stilmotor som er under utvikling og er meint å sameina dei 
ulike KDE-stilsystema.
 Comment[pt_BR]=Um mecanismo de estilo em desenvolvimento, destinado a unificar 
os vários sistemas de estilo do KDE.
 Comment[ro]=Un motor de stiluri aflat în dezvoltare ce are ca scop unificarea 
diferitelor sisteme de stilizare din KDE.
+Comment[ru]=Разрабатываемый механизм оформления, призванный объединить 
различные системы оформления в KDE.
 Comment[sk]=Vyvíjaný štýlovací engine určený na zjednotenie rôznych 
štýlovacích systémov v KDE.
 Comment[sl]=Slogovni mehanizem v razvoju, namenjen poenotenju različnih 
slogovnih sistemov v KDE.
 Comment[sr]=Механизам стилова у развоју, намењен уједначавању разних система 
стилизовања у КДЕ‑у.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/union-6.8.0/tools/styletool/CMakeLists.txt 
new/union-6.8.1/tools/styletool/CMakeLists.txt
--- old/union-6.8.0/tools/styletool/CMakeLists.txt      2026-10-08 
13:28:01.000000000 +0200
+++ new/union-6.8.1/tools/styletool/CMakeLists.txt      2026-10-20 
11:13:08.000000000 +0200
@@ -2,7 +2,7 @@
 # SPDX-FileCopyrightText: 2026 Arjen Hiemstra <[email protected]>
 
 add_executable(union-styletool)
-target_sources(union-styletool PRIVATE styletool.cpp)
+target_sources(union-styletool PRIVATE styletool.cpp TarArchive.cpp)
 
 target_link_libraries(union-styletool PRIVATE Union::Union Qt::Core ZLIB::ZLIB)
 target_compile_definitions(union-styletool PRIVATE 
PROJECT_VERSION="${PROJECT_VERSION}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/union-6.8.0/tools/styletool/Common.h 
new/union-6.8.1/tools/styletool/Common.h
--- old/union-6.8.0/tools/styletool/Common.h    2026-10-08 13:28:01.000000000 
+0200
+++ new/union-6.8.1/tools/styletool/Common.h    2026-10-20 11:13:08.000000000 
+0200
@@ -8,11 +8,14 @@
 #include <QCoreApplication>
 #include <QFile>
 #include <QStandardPaths>
+#include <QTemporaryDir>
 #include <QTextStream>
 
 #include <PackageHandler.h>
 #include <StylePackage.h>
 
+#include "TarArchive.h"
+
 using namespace Qt::StringLiterals;
 
 namespace fs = std::filesystem;
@@ -126,3 +129,33 @@
     std::cerr << "Operation on package " << package.path() << " failed: " << 
errorCode.message() << "\n";
     return errorCode.value();
 }
+
+std::pair<QTemporaryDir, fs::path> extractStyleArchive(const fs::path &path, 
std::error_code &errorCode)
+{
+    auto tempDir = QTemporaryDir{};
+    auto tempPath = fs::path(tempDir.path().toStdString());
+
+    Tar::TarArchive archive(path);
+    if (!archive.read(errorCode)) {
+        std::cerr << "Operation on package " << path << " failed: " << 
errorCode.message() << "\n";
+        return std::make_pair(std::move(tempDir), fs::path{});
+    }
+
+    if (!archive.extractAll(tempPath, errorCode)) {
+        std::cerr << "Operation on package " << path << " failed: " << 
errorCode.message() << "\n";
+        return std::make_pair(std::move(tempDir), fs::path{});
+    } else {
+        QList<fs::path> paths;
+        for (auto entry : fs::directory_iterator(tempPath)) {
+            paths.append(tempPath / entry.path());
+        }
+
+        if (paths.size() == 1) {
+            return std::make_pair(std::move(tempDir), paths.first());
+        }
+    }
+
+    std::cerr << "Operation on package " << path << " failed: The package is 
an invalid Union style package.\n";
+    errorCode = std::make_error_code(std::errc::io_error);
+    return std::make_pair(std::move(tempDir), fs::path{});
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/union-6.8.0/tools/styletool/Tar.h 
new/union-6.8.1/tools/styletool/Tar.h
--- old/union-6.8.0/tools/styletool/Tar.h       2026-10-08 13:28:01.000000000 
+0200
+++ new/union-6.8.1/tools/styletool/Tar.h       1970-01-01 01:00:00.000000000 
+0100
@@ -1,159 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR 
LicenseRef-KDE-Accepted-LGPL
-// SPDX-FileCopyrightText: 2026 Arjen Hiemstra 
<[email protected]>
-
-#pragma once
-
-#include <cstdint>
-#include <filesystem>
-#include <format>
-#include <iostream>
-
-#include <QByteArray>
-#include <QFile>
-#include <QFileInfo>
-#include <QList>
-
-extern "C" {
-#include <zlib.h>
-}
-
-/*
- * This is a very simple and naive implementation of creating an in-memory tar
- * archive that is written to disk with gzip compression. This avoids having to
- * drag in a complete
- */
-
-static constexpr uint8_t regularFileType = '0';
-static constexpr uint8_t directoryType = '5';
-
-// Header entry for an USTar format tar file
-struct USTarHeader {
-    char name[100] = {'\0'};
-    char mode[8] = {'\0'};
-    uint8_t uid[8] = {0};
-    uint8_t gid[8] = {0};
-    uint8_t size[12] = {0};
-    uint8_t mtime[12] = {0};
-    char checksum[8] = {0};
-    uint8_t type = {0};
-    uint8_t linkName[100] = {0};
-    uint8_t ustar[8] = "ustar  ";
-    uint8_t userName[32] = {0};
-    uint8_t groupName[32] = {0};
-    uint8_t deviceMajor[8] = {0};
-    uint8_t deviceMinor[8] = {0};
-    uint8_t namePrefix[155] = {0};
-    uint8_t padding[12] = {0};
-};
-
-struct TarEntry {
-    USTarHeader header;
-    QByteArray data;
-    QByteArray padding;
-};
-
-void tarDirectoryContents(const std::filesystem::path &directory, const 
std::filesystem::path &baseDirectory, QList<TarEntry> &output)
-{
-    for (auto entry : fs::directory_iterator(directory)) {
-        auto pathString = fs::relative(entry.path(), baseDirectory).string();
-        if (pathString.size() >= 100) {
-            std::cout << "Skipping entry " << pathString << " because the file 
name is too long.\n";
-            continue;
-        }
-
-        TarEntry tarEntry;
-
-        auto &header = tarEntry.header;
-        std::format_to_n(header.name, sizeof(header.name), "{}", pathString);
-        std::format_to_n(header.mode, sizeof(header.mode), "{:07o}", 
static_cast<int>(entry.status().permissions()));
-        std::format_to_n(header.size, sizeof(header.size), "{:011o}", 
entry.is_directory() ? 0 : entry.file_size());
-
-        QFileInfo fileInfo(entry.path());
-
-        std::format_to_n(header.uid, sizeof(header.uid), "{:07o}", 
fileInfo.ownerId());
-        std::format_to_n(header.gid, sizeof(header.uid), "{:07o}", 
fileInfo.groupId());
-        std::format_to_n(header.mtime, sizeof(header.mtime), "{:011o}", 
fileInfo.lastModified().toSecsSinceEpoch());
-
-        std::format_to_n(header.userName, sizeof(header.userName), "{}", 
fileInfo.owner().toStdString());
-        std::format_to_n(header.groupName, sizeof(header.groupName), "{}", 
fileInfo.group().toStdString());
-
-        if (entry.is_directory()) {
-            header.name[pathString.size()] = '/';
-            header.type = directoryType;
-        } else {
-            header.type = regularFileType;
-
-            QFile file(entry.path());
-            if (!file.open(QIODevice::ReadOnly)) {
-                std::cout << "Skipping entry " << pathString << " because it 
could not be opened.\n";
-                continue;
-            }
-
-            tarEntry.data = file.readAll();
-            tarEntry.padding = QByteArray{512 - tarEntry.data.size() % 512, 
'\0'};
-
-            file.close();
-        }
-
-        strncpy(header.checksum, "        ", sizeof(header.checksum));
-
-        auto headerData = reinterpret_cast<uint8_t *>(&header);
-        uint32_t checksum = 0;
-        for (int i = 0; i < 512; ++i) {
-            checksum += headerData[i];
-        }
-
-        std::format_to_n(header.checksum, sizeof(header.checksum), "{:06o}", 
checksum);
-        header.checksum[6] = '\0';
-        header.checksum[7] = ' ';
-
-        output.append(tarEntry);
-
-        if (entry.is_directory()) {
-            tarDirectoryContents(entry.path(), baseDirectory, output);
-        }
-    }
-}
-
-bool tarDirectory(const std::filesystem::path &directory, const 
std::filesystem::path &destination, std::error_code &errorCode)
-{
-    namespace fs = std::filesystem;
-
-    if (!fs::exists(directory)) {
-        errorCode = std::make_error_code(std::errc::no_such_file_or_directory);
-        return false;
-    }
-
-    if (!fs::is_directory(directory)) {
-        errorCode = std::make_error_code(std::errc::not_a_directory);
-        return false;
-    }
-
-    if (fs::exists(destination)) {
-        errorCode = std::make_error_code(std::errc::file_exists);
-        return false;
-    }
-
-    QList<TarEntry> entries;
-    tarDirectoryContents(directory, directory.parent_path(), entries);
-
-    QByteArray data;
-    for (const auto &entry : std::as_const(entries)) {
-        data.append(reinterpret_cast<const char *>(&entry.header), 
sizeof(USTarHeader));
-        data.append(entry.data);
-        data.append(entry.padding);
-    }
-
-    data.append(QByteArray{1024, '\0'});
-
-    auto outfile = gzopen(destination.string().data(), "wb");
-    if (!outfile) {
-        errorCode = std::error_code(errno, std::system_category());
-        return false;
-    }
-
-    gzwrite(outfile, data.data(), data.size());
-    gzclose(outfile);
-
-    return true;
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/union-6.8.0/tools/styletool/TarArchive.cpp 
new/union-6.8.1/tools/styletool/TarArchive.cpp
--- old/union-6.8.0/tools/styletool/TarArchive.cpp      1970-01-01 
01:00:00.000000000 +0100
+++ new/union-6.8.1/tools/styletool/TarArchive.cpp      2026-10-20 
11:13:08.000000000 +0200
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR 
LicenseRef-KDE-Accepted-LGPL
+// SPDX-FileCopyrightText: 2026 Arjen Hiemstra 
<[email protected]>
+
+#include "TarArchive.h"
+
+#include <format>
+#include <fstream>
+
+#include <QFileInfo>
+
+extern "C" {
+#include <zlib.h>
+}
+
+using namespace Tar;
+using namespace Qt::StringLiterals;
+
+namespace fs = std::filesystem;
+
+TarArchive::TarArchive()
+{
+}
+
+TarArchive::TarArchive(const std::filesystem::path &path)
+    : m_path(path)
+{
+}
+
+bool TarArchive::addEntry(const std::filesystem::path &path, std::error_code 
&errorCode)
+{
+    return addEntry(path, path.parent_path(), errorCode);
+}
+
+bool TarArchive::addEntry(const std::filesystem::path &path, const 
std::filesystem::path &baseDirectory, std::error_code &errorCode)
+{
+    QFileInfo fileInfo(path);
+
+    if (!fileInfo.exists()) {
+        errorCode = std::make_error_code(std::errc::no_such_file_or_directory);
+        return false;
+    }
+
+    if (m_path.empty() || !fs::is_directory(m_path.parent_path())) {
+        errorCode = std::make_error_code(std::errc::not_a_directory);
+        return false;
+    }
+
+    auto pathString = fs::relative(path, baseDirectory).string();
+    if (pathString.size() >= 100) {
+        errorCode = std::make_error_code(std::errc::filename_too_long);
+        return false;
+    }
+
+    TarEntry tarEntry;
+
+    auto &header = tarEntry.header;
+    std::format_to_n(header.name, sizeof(header.name), "{}", pathString);
+    std::format_to_n(header.mode, sizeof(header.mode), "{:07o}", 
static_cast<int>(fs::status(path).permissions()));
+    std::format_to_n(header.size, sizeof(header.size), "{:011o}", 
fileInfo.isDir() ? 0 : fileInfo.size());
+
+    std::format_to_n(header.uid, sizeof(header.uid), "{:07o}", 
fileInfo.ownerId());
+    std::format_to_n(header.gid, sizeof(header.uid), "{:07o}", 
fileInfo.groupId());
+    std::format_to_n(header.mtime, sizeof(header.mtime), "{:011o}", 
fileInfo.lastModified().toSecsSinceEpoch());
+
+    std::format_to_n(header.userName, sizeof(header.userName), "{}", 
fileInfo.owner().toStdString());
+    std::format_to_n(header.groupName, sizeof(header.groupName), "{}", 
fileInfo.group().toStdString());
+
+    if (fileInfo.isDir()) {
+        header.name[pathString.size()] = '/';
+        header.type = DirectoryType;
+    } else {
+        header.type = RegularFileType;
+
+        QFile file(path);
+        if (!file.open(QIODevice::ReadOnly)) {
+            errorCode = std::make_error_code(std::errc::io_error);
+            return false;
+        }
+
+        tarEntry.data = file.readAll();
+        tarEntry.padding = QByteArray{512 - tarEntry.data.size() % 512, '\0'};
+
+        file.close();
+    }
+
+    std::format_to_n(header.checksum, sizeof(header.checksum), "        ");
+
+    auto headerData = reinterpret_cast<uint8_t *>(&header);
+    uint32_t checksum = 0;
+    for (int i = 0; i < 512; ++i) {
+        checksum += headerData[i];
+    }
+
+    std::format_to_n(header.checksum, sizeof(header.checksum), "{:06o}", 
checksum);
+    header.checksum[6] = '\0';
+    header.checksum[7] = ' ';
+
+    m_entries.append(tarEntry);
+
+    if (fileInfo.isDir()) {
+        for (auto entry : fs::directory_iterator(path)) {
+            if (!addEntry(entry.path(), baseDirectory, errorCode)) {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+bool TarArchive::read(std::error_code &errorCode)
+{
+    m_entries.clear();
+
+    if (!fs::exists(m_path)) {
+        errorCode = std::make_error_code(std::errc::no_such_file_or_directory);
+        return false;
+    }
+
+    auto infile = gzopen(m_path.string().data(), "rb");
+    if (!infile) {
+        errorCode = std::error_code(errno, std::system_category());
+        return false;
+    }
+
+    constexpr int BufferSize = 1024;
+    QByteArray data;
+    std::array<char, BufferSize> buffer;
+    while (true) {
+        int read = gzread(infile, buffer.data(), buffer.size());
+        if (read == BufferSize) {
+            data.append(buffer);
+        } else if (read > 0) {
+            data.append(buffer);
+            break;
+        } else {
+            errorCode = std::make_error_code(std::errc::io_error);
+            return false;
+        }
+    }
+
+    if (data.size() == 0) {
+        errorCode = std::make_error_code(std::errc::io_error);
+        return false;
+    }
+
+    constexpr int ChunkSize = 512;
+    auto offset = 0;
+    auto remainingSize = data.size();
+    auto view = QByteArrayView(data);
+    TarEntry currentEntry;
+    bool first = true;
+    while (remainingSize > 0) {
+        auto chunk = view.sliced(offset, ChunkSize);
+        remainingSize -= ChunkSize;
+        offset += ChunkSize;
+
+        if (chunk.sliced(257, 5) == "ustar") {
+            if (!first) {
+                currentEntry.data = currentEntry.data.sliced(0, 
currentEntry.header.actualSize());
+                m_entries.append(currentEntry);
+                currentEntry = TarEntry{};
+            } else {
+                currentEntry = TarEntry{};
+                first = false;
+            }
+
+            memcpy(&currentEntry.header, chunk.data(), ChunkSize);
+        } else {
+            currentEntry.data.append(chunk);
+        }
+    }
+
+    currentEntry.data = currentEntry.data.sliced(0, 
currentEntry.header.actualSize());
+    m_entries.append(currentEntry);
+    currentEntry = TarEntry{};
+
+    return true;
+}
+
+bool TarArchive::write(std::error_code &errorCode)
+{
+    if (fs::exists(m_path)) {
+        errorCode = std::make_error_code(std::errc::file_exists);
+        return false;
+    }
+
+    QByteArray data;
+    for (const auto &entry : std::as_const(m_entries)) {
+        data.append(reinterpret_cast<const char *>(&entry.header), 
sizeof(USTarHeader));
+        data.append(entry.data);
+        data.append(entry.padding);
+    }
+
+    data.append(QByteArray{1024, '\0'});
+
+    auto outfile = gzopen(m_path.string().data(), "wb");
+    if (!outfile) {
+        errorCode = std::error_code(errno, std::system_category());
+        return false;
+    }
+
+    gzwrite(outfile, data.data(), data.size());
+    gzclose(outfile);
+
+    return true;
+}
+
+bool Tar::TarArchive::extract(const std::string &name, const 
std::filesystem::path &destination, std::error_code &errorCode)
+{
+    if (!fs::is_directory(destination)) {
+        errorCode = std::make_error_code(std::errc::not_a_directory);
+        return false;
+    }
+
+    auto itr = std::ranges::find_if(m_entries, [&name](const TarEntry &entry) {
+        return entry.header.name == name;
+    });
+    if (itr == m_entries.end()) {
+        errorCode = std::make_error_code(std::errc::no_such_file_or_directory);
+        return false;
+    }
+
+    return extractEntry(destination, *itr, errorCode);
+}
+
+bool Tar::TarArchive::extractAll(const std::filesystem::path &destination, 
std::error_code &errorCode)
+{
+    if (!fs::is_directory(destination)) {
+        errorCode = std::make_error_code(std::errc::not_a_directory);
+        return false;
+    }
+
+    for (const auto &entry : std::as_const(m_entries)) {
+        if (!extractEntry(destination, entry, errorCode)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool TarArchive::extractEntry(const std::filesystem::path &destination, const 
TarEntry &entry, std::error_code &errorCode)
+{
+    Q_ASSERT(fs::is_directory(destination));
+
+    auto destinationPath = destination / entry.header.name;
+    if (fs::exists(destinationPath)) {
+        errorCode = std::make_error_code(std::errc::file_exists);
+        return false;
+    }
+
+    if (entry.header.type == RegularFileType) {
+        if (!fs::exists(destinationPath.parent_path())) {
+            errorCode = std::make_error_code(std::errc::not_a_directory);
+            return false;
+        }
+
+        std::ofstream stream(destinationPath, std::ios::binary);
+        stream.write(entry.data.data(), entry.data.size());
+        stream.close();
+
+        if (stream.fail()) {
+            errorCode = std::make_error_code(std::errc::io_error);
+            return false;
+        } else {
+            return true;
+        }
+    } else if (entry.header.type == DirectoryType) {
+        fs::create_directories(destinationPath, errorCode);
+        if (errorCode) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    errorCode = std::make_error_code(std::errc::operation_not_supported);
+    return false;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/union-6.8.0/tools/styletool/TarArchive.h 
new/union-6.8.1/tools/styletool/TarArchive.h
--- old/union-6.8.0/tools/styletool/TarArchive.h        1970-01-01 
01:00:00.000000000 +0100
+++ new/union-6.8.1/tools/styletool/TarArchive.h        2026-10-20 
11:13:08.000000000 +0200
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR 
LicenseRef-KDE-Accepted-LGPL
+// SPDX-FileCopyrightText: 2026 Arjen Hiemstra 
<[email protected]>
+
+#pragma once
+
+#include <cstdint>
+#include <filesystem>
+
+#include <QByteArray>
+#include <QList>
+
+namespace Tar
+{
+
+static constexpr uint8_t RegularFileType = '0';
+static constexpr uint8_t DirectoryType = '5';
+
+/* Header entry for an USTar format tar file
+ */
+struct USTarHeader {
+    char name[100] = {'\0'};
+    char mode[8] = {'\0'};
+    uint8_t uid[8] = {0};
+    uint8_t gid[8] = {0};
+    uint8_t size[12] = {0};
+    uint8_t mtime[12] = {0};
+    char checksum[8] = {0};
+    uint8_t type = {0};
+    uint8_t linkName[100] = {0};
+    uint8_t ustar[8] = "ustar  ";
+    uint8_t userName[32] = {0};
+    uint8_t groupName[32] = {0};
+    uint8_t deviceMajor[8] = {0};
+    uint8_t deviceMinor[8] = {0};
+    uint8_t namePrefix[155] = {0};
+    uint8_t padding[12] = {0};
+
+    inline int actualSize() const
+    {
+        QByteArrayView sizeData(size, 11);
+        return sizeData.toInt(nullptr, 8);
+    }
+};
+
+/* A single entry in a tar file.
+ */
+struct TarEntry {
+    USTarHeader header;
+    QByteArray data;
+    QByteArray padding;
+};
+
+/*
+ * This is a very simple and naive implementation of creating an in-memory tar
+ * archive that is written to disk with gzip compression. This avoids having to
+ * drag in a complete archival library just to write a single package format.
+ */
+class TarArchive
+{
+public:
+    TarArchive();
+    TarArchive(const std::filesystem::path &path);
+
+    bool addEntry(const std::filesystem::path &path, std::error_code 
&errorCode);
+    bool addEntry(const std::filesystem::path &path, const 
std::filesystem::path &baseDirectory, std::error_code &errorCode);
+
+    bool read(std::error_code &errorCode);
+    bool write(std::error_code &errorCode);
+
+    bool extract(const std::string &name, const std::filesystem::path 
&destination, std::error_code &errorCode);
+    bool extractAll(const std::filesystem::path &destination, std::error_code 
&errorCode);
+
+private:
+    bool extractEntry(const std::filesystem::path &destination, const TarEntry 
&entry, std::error_code &errorCode);
+
+    std::filesystem::path m_path;
+    QList<TarEntry> m_entries;
+};
+
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/union-6.8.0/tools/styletool/styletool.cpp 
new/union-6.8.1/tools/styletool/styletool.cpp
--- old/union-6.8.0/tools/styletool/styletool.cpp       2026-10-08 
13:28:01.000000000 +0200
+++ new/union-6.8.1/tools/styletool/styletool.cpp       2026-10-20 
11:13:08.000000000 +0200
@@ -9,7 +9,7 @@
 #include <StyleRegistry.h>
 
 #include "Common.h"
-#include "Tar.h"
+#include "TarArchive.h"
 
 int handleInstallCommand([[maybe_unused]] const QStringList &arguments)
 {
@@ -25,12 +25,26 @@
     auto packageName = parser->positionalArguments().first();
     auto packagePath = fs::absolute(fs::path(packageName.toStdString()));
 
-    auto package = Union::StylePackage{packagePath};
+    Union::StylePackage package;
+
+    std::error_code errorCode;
+    std::optional<QTemporaryDir> tempDir;
+    if (packagePath.extension() == ".unionstyle") {
+        auto [dir, path] = extractStyleArchive(packagePath, errorCode);
+        if (errorCode) {
+            return errorCode.value();
+        } else {
+            tempDir = std::move(dir);
+            package = Union::StylePackage(path);
+        }
+    } else {
+        package = Union::StylePackage{packagePath};
+    }
+
     if (!package.isValid()) {
         return printPackageError(package);
     }
 
-    std::error_code errorCode;
     auto handler = Union::StyleRegistry::instance()->packageHandler();
     if (!handler->install(package, errorCode)) {
         return printErrorCode(package, errorCode);
@@ -142,19 +156,33 @@
     }
 
     auto pathOrId = parser->positionalArguments().first();
+    auto packagePath = fs::absolute(fs::path(pathOrId.toStdString()));
 
-    auto handler = Union::StyleRegistry::instance()->packageHandler();
+    Union::StylePackage package;
+    std::error_code errorCode;
+    std::optional<QTemporaryDir> tempDir;
 
-    auto package = handler->package(pathOrId);
-    if (!package.isValid()) {
-        package = 
Union::StylePackage{fs::absolute(fs::path(pathOrId.toStdString()))};
+    if (!fs::exists(packagePath)) {
+        auto handler = Union::StyleRegistry::instance()->packageHandler();
+        package = handler->package(pathOrId);
+        packagePath = package.path();
+    } else if (packagePath.extension() == ".unionstyle") {
+        auto [dir, path] = extractStyleArchive(packagePath, errorCode);
+        if (errorCode) {
+            return errorCode.value();
+        } else {
+            tempDir = std::move(dir);
+            package = Union::StylePackage(path);
+        }
+    } else {
+        package = Union::StylePackage(packagePath);
     }
 
     if (!package.isValid()) {
         return printPackageError(package);
     }
 
-    std::cout << "Path:        " << package.path().string() << "\n";
+    std::cout << "Path:        " << packagePath.string() << "\n";
     std::cout << "Input Type:  " << qPrintable(package.inputType()) << "\n";
     std::cout << "Name:        " << qPrintable(package.name()) << "\n";
     std::cout << "Description: " << qPrintable(package.description()) << "\n";
@@ -221,7 +249,23 @@
     }
 
     auto packageName = parser->positionalArguments().first();
-    auto package = 
Union::StylePackage{fs::absolute(fs::path(packageName.toStdString()))};
+    auto packagePath = fs::absolute(fs::path(packageName.toStdString()));
+
+    Union::StylePackage package;
+
+    std::error_code errorCode;
+    std::optional<QTemporaryDir> tempDir;
+    if (packagePath.extension() == ".unionstyle") {
+        auto [dir, path] = extractStyleArchive(packagePath, errorCode);
+        if (errorCode) {
+            return errorCode.value();
+        } else {
+            tempDir = std::move(dir);
+            package = Union::StylePackage(path);
+        }
+    } else {
+        package = Union::StylePackage{packagePath};
+    }
 
     if (!package.isValid()) {
         return printPackageError(package);
@@ -232,7 +276,6 @@
         flags |= Union::PackageHandler::OperationFlag::SkipVersionCheck;
     }
 
-    std::error_code errorCode;
     auto handler = Union::StyleRegistry::instance()->packageHandler();
     if (!handler->update(package, errorCode, flags)) {
         return printErrorCode(package, errorCode);
@@ -299,8 +342,13 @@
     auto packagedPath = fs::current_path() / QString{package.id() + 
u".unionstyle"}.toStdString();
 
     std::error_code errorCode;
-    tarDirectory(package.path(), packagedPath, errorCode);
-    if (errorCode) {
+
+    Tar::TarArchive archive(packagedPath);
+    if (!archive.addEntry(package.path(), errorCode)) {
+        return printErrorCode(package, errorCode);
+    }
+
+    if (!archive.write(errorCode)) {
         return printErrorCode(package, errorCode);
     }
 

Reply via email to