diff --git a/coverage.xml b/coverage.xml index 8046566..ca939d6 100644 --- a/coverage.xml +++ b/coverage.xml @@ -1,12 +1,12 @@ - + C:\Users\asp\Documents\Code\repos\torrentfileQt - + @@ -15,13 +15,14 @@ - + - - + + + @@ -30,75 +31,75 @@ - - + - + - + + - + - - + + - - + + - - - + + - - - - + + + + - - + + - - + + + @@ -123,16 +124,16 @@ - - - + + + @@ -154,14 +155,6 @@ - - - - - - - - @@ -171,16 +164,16 @@ - - + + + - - + + - + - @@ -196,9 +189,9 @@ - + + - @@ -206,9 +199,9 @@ - + + - @@ -227,10 +220,10 @@ - - + + + - @@ -241,8 +234,8 @@ + - @@ -253,14 +246,22 @@ - + + - + + + + + + + + @@ -400,6 +401,7 @@ + @@ -495,27 +497,28 @@ - + + - - + + - - - - - + + + + + - + + - @@ -523,22 +526,19 @@ - - - - - + + - - + + @@ -552,90 +552,115 @@ + + + - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + - - - - - + + + + + - - + + - - + + + + + + + - - + + - - - + + - - - - + + + - - - - - + + + @@ -643,12 +668,9 @@ - - - - + @@ -664,8 +686,7 @@ - - + @@ -683,103 +704,95 @@ - + - + - - + + - + - - + + - + - - + + - + - + - + - + - - + + - + - - + + - - + + - - - + + + - - - - - - - + + + + + + + - - - - - - - - - - + + + + + + + + + + - + - - + + + + - - - - - - - - - - - + - + @@ -805,7 +818,7 @@ - + @@ -927,10 +940,6 @@ - - - - @@ -1122,7 +1131,7 @@ - + @@ -1242,10 +1251,10 @@ - - - - + + + + @@ -1297,9 +1306,9 @@ - - - + + + @@ -1307,22 +1316,22 @@ - - + + - - - + + + - - + + @@ -1330,22 +1339,22 @@ - + - - - + + + - - + + @@ -1353,26 +1362,25 @@ - + - - - + + + - + - + - + - @@ -1475,14 +1483,14 @@ - - + + - - - + + + @@ -1503,14 +1511,14 @@ - - + + - - - - + + + + @@ -1522,15 +1530,15 @@ - + - - + + @@ -1545,22 +1553,22 @@ - + - - - + + + - - - - + + + + @@ -1568,10 +1576,10 @@ - - - + + + @@ -1585,13 +1593,15 @@ + - + - + + @@ -1910,89 +1920,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -2042,21 +1970,21 @@ - - + + - - + + - - - - - + + + + + - - - + + + @@ -2073,12 +2001,12 @@ - - - - - - + + + + + + @@ -2090,53 +2018,52 @@ - - + + - + - - + + - + - - + - + - + - + - - - + + + - - + + @@ -2148,7 +2075,7 @@ - + @@ -2156,7 +2083,6 @@ - @@ -2167,11 +2093,191 @@ - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2193,21 +2299,21 @@ - + - + - - - - - - + + + + + + @@ -2217,22 +2323,24 @@ - - - + + + + - - + + - - + + + @@ -2250,6 +2358,8 @@ + + @@ -2292,35 +2402,33 @@ - - - - - - + + + + + + - - - - + + + + - - - + + + + + - - - - - + + + + + - - - - @@ -2330,7 +2438,7 @@ - + @@ -2401,7 +2509,6 @@ - diff --git a/tests/__init__.py b/tests/__init__.py index cfc9bb4..fbc4ea0 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -33,6 +33,7 @@ from torrentfileQt import Application APP = Application([]) +# APP.window.show() def exception_hook(exctype, value, traceback): # pragma: no cover @@ -295,23 +296,7 @@ def mime_data(self): mimeData = mime_data -class MockQFileDialog: - """Mock object for the QFileDialog.""" - - Out = None - - @classmethod - def getOpenFileName(cls, parent=None, dir=None, caption=None): - """Mock class method for returning file path from file dialog.""" - assert isinstance(caption, str) - assert dir - cls.parent = parent - return cls.Out - - getExistingDirectory = getOpenFileName - - -def proc_time(amount=0.1): +def proc_time(amount=0.01): """Process time span with updating GUI.""" then = time.time() APP.processEvents() diff --git a/tests/test_checktab.py b/tests/test_checktab.py index 26bc7ef..d04ab14 100644 --- a/tests/test_checktab.py +++ b/tests/test_checktab.py @@ -21,12 +21,9 @@ import os from pathlib import Path -import PySide6 import pytest -from tests import (MockQFileDialog, dir1, dir2, proc_time, rmpath, tempfile, - ttorrent, wind) -from torrentfileQt import checkTab +from tests import dir1, dir2, proc_time, rmpath, tempfile, ttorrent, wind from torrentfileQt.checkTab import ProgressBar, TreePieceItem, TreeWidget @@ -89,8 +86,6 @@ def test_check_tab(wind, ttorrent, dir1): def test_check_tab_input1(wind, dir1): """Test checker procedure.""" checktab = wind.central.checkWidget - MockQFileDialog.Out = dir1 - PySide6.QtWidgets.QFileDialog = MockQFileDialog wind.central.setCurrentWidget(checktab) checktab.browseButton2.browse_folders(dir1) assert checktab.searchInput.text() != "" @@ -99,8 +94,6 @@ def test_check_tab_input1(wind, dir1): def test_check_tab_input_2(wind, dir1): """Test checker procedure.""" checktab = wind.central.checkWidget - MockQFileDialog.Out = dir1 - PySide6.QtWidgets.QFileDialog = MockQFileDialog wind.central.setCurrentWidget(checktab) checktab.browseButton1.browse((dir1, None)) assert checktab.fileInput.text() != "" @@ -147,7 +140,6 @@ def test_singlefile(size, ext, index, version, wind): testfile = str(tempfile(exp=size)) tfile = testfile + ext os.rename(testfile, tfile) - checkTab.QFileDialog = MockQFileDialog metafile = tfile + ".torrent" createtab.path_input.clear() createtab.output_input.clear() diff --git a/tests/test_createTab.py b/tests/test_createTab.py index 788f16d..b27b60f 100644 --- a/tests/test_createTab.py +++ b/tests/test_createTab.py @@ -20,8 +20,10 @@ import pyben import pytest +from torrentfile.torrent import TorrentFileHybrid from tests import dir1, dir2, proc_time, rmpath, tempfile, wind +from torrentfileQt.createTab import TorrentFileCreator def test_rmpath(): @@ -143,3 +145,12 @@ def test_sized_create(wind): button.browse(param) proc_time() assert createtab.path_input.text() == path + + +def test_torrentfile_creator(dir1): + """Test the QThread torrent file creator.""" + args = {"path": dir1, "outfile": dir1 + ".torrent"} + creator = TorrentFileCreator(args, TorrentFileHybrid) + creator.run() + assert os.path.exists(dir1 + ".torrent") + rmpath(dir1 + ".torrent") diff --git a/tests/test_gui.py b/tests/test_gui.py index 058b726..58ab8e5 100644 --- a/tests/test_gui.py +++ b/tests/test_gui.py @@ -135,4 +135,5 @@ def test_styleManager(): manager = StyleManager(themes) manager.current = themes["test"] collection = manager.parser.parse(themes["test"]) + manager.parser._compile() assert len(collection) > 1 diff --git a/tests/test_magnettab.py b/tests/test_tooltab.py similarity index 58% rename from tests/test_magnettab.py rename to tests/test_tooltab.py index f89ce08..85c204e 100644 --- a/tests/test_magnettab.py +++ b/tests/test_tooltab.py @@ -44,17 +44,18 @@ def torrent(dir1): def test_fixture(): """Testing pytest fixtures.""" - assert [dir1, tempfile, wind, ttorrent, dir2] + assert [dir1, dir2, tempfile, wind, ttorrent] def test_create_magnet(wind, torrent): """Test creating Magnet URI from a torrent file path.""" outfile, _ = torrent - tab = wind.central.magnetWidget + tab = wind.central.toolWidget wind.central.setCurrentWidget(tab) - tab.metafile_input.setText(str(outfile)) - tab.submit_button.click() - out = tab.output.text() + widget = tab.magnetgroup + widget.pathEdit.setText(str(outfile)) + widget.submit_button.click() + out = widget.magnetEdit.text() proc_time() assert out == magnet(outfile) @@ -62,50 +63,75 @@ def test_create_magnet(wind, torrent): def test_create_magnet_method(wind, torrent): """Test creating Magnet URI from a torrent file path.""" outfile, _ = torrent - tab = wind.central.magnetWidget + tab = wind.central.toolWidget wind.central.setCurrentWidget(tab) - tab.file_button.select_metafile(outfile) + tab = tab.magnetgroup + tab.metafilebutton.select_metafile(outfile) tab.submit_button.magnet() - out = tab.output.text() + out = tab.magnetEdit.text() proc_time() assert out == magnet(outfile) def test_magnet_accept_method(wind, ttorrent): """Test drag enter event on editor widget.""" - magnet = wind.central.magnetWidget - magnet.window.central.setCurrentWidget(magnet) + tab = wind.central.toolWidget + tab.window.central.setCurrentWidget(tab) proc_time() event = MockEvent(ttorrent) - assert magnet.dragEnterEvent(event) + assert tab.magnetgroup.dragEnterEvent(event) event = MockEvent(None) - assert not magnet.dragEnterEvent(event) + assert not tab.magnetgroup.dragEnterEvent(event) def test_magnet_move_event(wind, ttorrent): """Test move event on magnet widget.""" - magnet = wind.central.magnetWidget - magnet.window.central.setCurrentWidget(magnet) + tools = wind.central.toolWidget + tools.window.central.setCurrentWidget(tools) proc_time() event = MockEvent(ttorrent) - assert magnet.dragMoveEvent(event) + assert tools.magnetgroup.dragMoveEvent(event) event = MockEvent(None) - assert not magnet.dragMoveEvent(event) + assert not tools.magnetgroup.dragMoveEvent(event) def test_magnet_drop_event(wind, ttorrent): """Test drop event on editor widget.""" - magnet = wind.central.magnetWidget - magnet.window.central.setCurrentWidget(magnet) + tools = wind.central.toolWidget + tools.window.central.setCurrentWidget(tools) proc_time() event = MockEvent(ttorrent) - assert magnet.dropEvent(event) + assert tools.magnetgroup.dropEvent(event) def test_magnet_drop_false(wind): """Test drop event on editor widget returns None.""" - magnet = wind.central.magnetWidget - magnet.window.central.setCurrentWidget(magnet) + tools = wind.central.toolWidget + tools.window.central.setCurrentWidget(tools) proc_time() event = MockEvent(None) - assert not magnet.dropEvent(event) + assert not tools.magnetgroup.dropEvent(event) + + +def test_piecelengthcalculator(wind, dir1): + """Test the piece length calculator.""" + tools = wind.central.toolWidget + tools.window.central.setCurrentWidget(tools) + proc_time() + calculator = tools.piece_length_calculator + calculator.browse_folders(dir1) + assert calculator.path_line.text() == dir1 + + +def test_piecelengthcalculator_file(wind): + """Test the piece length calculator with a single file.""" + widget = wind.central.toolWidget + widget.window.central.setCurrentWidget(widget) + proc_time() + calculator = widget.piece_length_calculator + temp = str(tempfile()) + calculator.browse_files(temp) + assert calculator.path_line.text() == temp + calculator.piece_length_combo.setCurrentIndex(3) + calculator.calculate_piece_length() + rmpath(temp) diff --git a/torrentfileQt/assets/minus.png b/torrentfileQt/assets/minus.png new file mode 100644 index 0000000..f8e112a Binary files /dev/null and b/torrentfileQt/assets/minus.png differ diff --git a/torrentfileQt/assets/plus.png b/torrentfileQt/assets/plus.png index 1a4abb1..7e881fb 100644 Binary files a/torrentfileQt/assets/plus.png and b/torrentfileQt/assets/plus.png differ diff --git a/torrentfileQt/checkTab.py b/torrentfileQt/checkTab.py index 4d7fc7e..4899237 100644 --- a/torrentfileQt/checkTab.py +++ b/torrentfileQt/checkTab.py @@ -213,7 +213,7 @@ def __init__(self, parent=None): self.setIcon(QIcon(get_icon("browse_file"))) self.clicked.connect(self.browse_files) - def browse_files(self, path=None): + def browse_files(self, path=None): # pragma: nocover """ Browse Action performed when user presses button. """ diff --git a/torrentfileQt/createTab.py b/torrentfileQt/createTab.py index d7d20dc..c8f5fd6 100644 --- a/torrentfileQt/createTab.py +++ b/torrentfileQt/createTab.py @@ -182,7 +182,7 @@ class TorrentFileCreator(QThread): container to add return values to """ - created = Signal([str]) + created = Signal() def __init__(self, args, creator): """Construct the new thread.""" @@ -194,8 +194,8 @@ def run(self): """Create a torrent file and emit it's path.""" args = deepcopy(self.args) torrent = self.creator(**args) - outfile, _ = torrent.write() - self.created.emit(outfile) + _, _ = torrent.write() + self.created.emit() class SubmitButton(QPushButton): @@ -279,10 +279,9 @@ def updateStatusBarBegin(self): """Update the status bar when torrent creation is complete.""" self.window.statusBar().showMessage("Processing", 3000) - def updateStatusBarEnd(self, string): + def updateStatusBarEnd(self): """Update the status bar when torrent creation is complete.""" - message = f"Finished creating torrent file: {string}" - self.window.statusBar().showMessage(message, 3000) + self.window.statusBar().showMessage("Completed", 3000) class OutButton(QPushButton): diff --git a/torrentfileQt/editorTab.py b/torrentfileQt/editorTab.py index 96b2061..b1ae04c 100644 --- a/torrentfileQt/editorTab.py +++ b/torrentfileQt/editorTab.py @@ -23,13 +23,13 @@ import pyben from PySide6.QtCore import Qt, Signal -from PySide6.QtGui import QAction +from PySide6.QtGui import QAction, QIcon from PySide6.QtWidgets import (QComboBox, QHBoxLayout, QLabel, QLineEdit, QPushButton, QSizePolicy, QTableWidget, - QTableWidgetItem, QToolBar, QToolButton, - QVBoxLayout, QWidget) + QTableWidgetItem, QToolBar, QVBoxLayout, + QWidget) -from torrentfileQt.utils import browse_torrent +from torrentfileQt.utils import browse_torrent, get_icon class EditorWidget(QWidget): @@ -141,14 +141,15 @@ def save(self): pyben.dump(meta, text) -class FileButton(QToolButton): +class FileButton(QPushButton): """Tool Button for selecting a .torrent file to edit.""" def __init__(self, parent=None): """Construct for the FileDialog button on Torrent Editor tab.""" super().__init__(parent=parent) self.widget = parent - self.setText("Select File") + self.setIcon(QIcon(get_icon("browse_file"))) + self.setText("File") self.window = parent.window self.clicked.connect(self.browse) @@ -168,7 +169,6 @@ def __init__(self, parent): super().__init__(parent) self.setProperty("editButton", "true") self.parent = parent - self.setText("add") self.box = None self.triggered.connect(self.add_item) @@ -191,7 +191,6 @@ def __init__(self, parent): super().__init__(parent) self.setProperty("editButton", "true") self.parent = parent - self.setText("remove") self.box = None self.triggered.connect(self.remove_item) @@ -220,7 +219,6 @@ def __init__(self, parent=None): vheader = self.verticalHeader() vheader.setSectionResizeMode(vheader.ResizeMode.Stretch) vheader.setHidden(True) - self.setHorizontalHeaderLabels(["Label", "Value"]) self.handleTorrent.connect(self.export_data) def clear(self): @@ -230,6 +228,7 @@ def clear(self): self.removeRow(row) self.setRowCount(0) super().clear() + self.setHorizontalHeaderLabels(["Label", "Value"]) def export_data(self, path): """Export slot for the handleTorrent signal.""" @@ -287,7 +286,6 @@ def __init__(self, parent=None): """Construct a combobox for table widget cell.""" super().__init__(parent=parent) self.widget = parent - self.setProperty("editCombo", "true") self.sizePolicy().setVerticalPolicy(QSizePolicy.Minimum) self.setMinimumContentsLength(48) self.sizePolicy().setHorizontalPolicy(QSizePolicy.Minimum) @@ -318,15 +316,19 @@ class ToolBar(QToolBar): def __init__(self, parent=None): """Construct the toolbar instance.""" super().__init__(parent=parent) + self.setProperty("editToolBar", "true") self.sizePolicy().setHorizontalPolicy(QSizePolicy.Minimum) self.setMinimumWidth(800) self.line_edit = QLineEdit(parent=self) self.combo = Combo(self) self.combo.setLineEdit(self.line_edit) - self.setProperty("editLine", "true") self.add_button = AddItemButton(self) + addIcon = QIcon(get_icon("plus")) + self.add_button.setIcon(addIcon) self.add_button.box = self.combo self.remove_button = RemoveItemButton(self) + removeIcon = QIcon(get_icon("minus")) + self.remove_button.setIcon(removeIcon) self.remove_button.box = self.combo self.addWidget(self.combo) self.addActions([self.add_button, self.remove_button]) diff --git a/torrentfileQt/magnetTab.py b/torrentfileQt/magnetTab.py deleted file mode 100644 index 322310b..0000000 --- a/torrentfileQt/magnetTab.py +++ /dev/null @@ -1,131 +0,0 @@ -#! /usr/bin/python3 -# -*- coding: utf-8 -*- - -############################################################################## -# Copyright 2020 AlexPDev -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -############################################################################## -"""Magnet Widget containing Testing creation of Magnet URIs.""" - -import os - -from PySide6.QtCore import Qt -from PySide6.QtWidgets import (QHBoxLayout, QLabel, QLineEdit, QPushButton, - QSpacerItem, QToolButton, QVBoxLayout, QWidget) -from torrentfile import magnet - -from torrentfileQt.utils import browse_torrent - - -class MagnetWidget(QWidget): - """Tab for creating magnet URL's and downloading torrentfiles from them.""" - - def __init__(self, parent=None): - """Initialize the widget for creating magnet URI's from a metafile.""" - super().__init__(parent=parent) - self.window = parent.window - self.layout = QVBoxLayout() - self.setLayout(self.layout) - self.hlayout = QHBoxLayout() - self.top_spacer = QSpacerItem(0, 50) - self.bottom_spacer = QSpacerItem(0, 100) - self.metafile_label = QLabel("Torrent Meta File", parent=self) - self.magnet_label = QLabel("Magnet Link", parent=self) - self.magnet_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - self.metafile_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - self.metafile_input = QLineEdit(parent=self) - self.output = QLineEdit(parent=self) - self.file_button = MetafileButton(parent=self) - self.submit_button = SubmitButton(parent=self) - self.hlayout = QHBoxLayout() - self.hlayout.addWidget(self.metafile_input) - self.hlayout.addWidget(self.file_button) - self.layout.addSpacerItem(self.top_spacer) - self.layout.addWidget(self.metafile_label) - self.layout.addLayout(self.hlayout) - self.layout.addWidget(self.magnet_label) - self.layout.addWidget(self.output) - self.layout.addWidget(self.submit_button) - self.layout.addSpacerItem(self.bottom_spacer) - self.setAcceptDrops(True) - - def dragEnterEvent(self, event): - """Drag enter event for widget.""" - if event.mimeData().hasUrls: - self.urls = event.mimeData().urls() - event.accept() - return True - return event.ignore() - - def dragMoveEvent(self, event): - """Drag Move Event for widgit.""" - if event.mimeData().hasUrls: - self.urls = event.mimeData().urls() - event.accept() - return True - return event.ignore() - - def dropEvent(self, evt): - """Drag drop event for widgit.""" - urls = evt.mimeData().urls() - loc = urls[0].toLocalFile() - if os.path.exists(loc): - self.metafile_input.setText(loc) - self.submit_button.click() - return True - return False - - -class SubmitButton(QPushButton): - """Submit current information to be processed into a megnet URI.""" - - def __init__(self, parent=None): - """Initialize the button for magnet creation.""" - super().__init__(parent=parent) - self.widget = parent - self.window = parent.window - self.setText("Create Magnet") - self.clicked.connect(self.magnet) - - def magnet(self): - """Create a magnet URI from information contained in form.""" - fd = self.widget.metafile_input.text() - if os.path.exists(fd): - uri = magnet(fd) - self.widget.output.setText(uri) - - -class MetafileButton(QToolButton): - """ - Find a .torrent file in native file browser button actions. - - Perameters - ---------- - parent : `QWidget` - This widgets parent. - """ - - def __init__(self, parent=None): - """Initialize the metafile button.""" - super().__init__(parent=parent) - self.window = parent.window - self.widget = parent - self.setText("Select File") - self.setCursor(Qt.CursorShape.PointingHandCursor) - self.pressed.connect(self.select_metafile) - - def select_metafile(self, path=None): - """Find metafile in file browser.""" - path = browse_torrent(self, path) - self.widget.metafile_input.setText(path) diff --git a/torrentfileQt/menu.py b/torrentfileQt/menu.py index 6e560ae..042dcf4 100644 --- a/torrentfileQt/menu.py +++ b/torrentfileQt/menu.py @@ -93,8 +93,7 @@ def __init__(self, title, parent): def exit_app(self): """Close application.""" - app = self.parent().window.app - app.quit() # pragma: nocover + self.parent().window.app.quit() # pragma: nocover def light_theme(self): """Change the GUI theme for the application.""" @@ -223,7 +222,7 @@ def add_profile(self, name=None): piece_length_index = tab.piece_length.currentIndex() piece_length = tab.piece_length.itemData(piece_length_index) if tab.hybridbutton.isChecked(): - version = 3 + version = 3 # pragma: nocover elif tab.v2button.isChecked(): version = 2 else: diff --git a/torrentfileQt/qss.py b/torrentfileQt/qss.py index 777b0b2..bd09e72 100644 --- a/torrentfileQt/qss.py +++ b/torrentfileQt/qss.py @@ -22,8 +22,9 @@ from torrentfileQt.utils import get_icon -arrow = os.path.join(get_icon("arrow-down.png")) -dark_theme = """ +arrow = path2url(os.path.relpath(get_icon("arrow-down"), os.getcwd())) + +dark_theme = (""" * { background-color: #19232D; color: #FFFFFF; @@ -64,25 +65,51 @@ border-color: #f61; selection-background-color: #2f4f4f; } -QLabel, -QLabel:disabled { - border-width: 1px; - background-color: transparent; +*[editToolBar="true"] { + background-color: #3a3a3a; + spacing: 3px; +} +*[editToolBar="true"] QComboBox { + background-color: #000; + margin-left: 6px; + border: 1px inset #f71; + border-radius: 4px; + font-size: 9pt; + padding: 3px; +} +*[editToolBar="true"] QComboBox QLineEdit { + margin: 0px; padding: 0px; - font-size: 8pt; - border-color: transparent; - selection-background-color: #2f4f4f; } -QMainWindow::separator { - background: #000; - border-width: 0px; +*[createButton="true"] { + padding: 3px; + margin: 0px; + font-size: 9pt; } -QMainWindow::separator:hover { - background: transparent; +*[editCombo="true"] { + font-size: 12pt; + margin: 0px 0px 0px 0px; + border-width: 1px; + padding: 0px 0px 0px 0px; + min-height: 19px; } -QWidget { - background-color: #39434d; - border-width: 0px; +*[editButton="true"] { + margin-left: 2px; + margin-right: 2px; + font-size: 10pt; + border-radius: 12px; +} +*[infoLine="true"] { + background-color: transparent; + color: #FFF; + border-radius: 0px; + border-width: 2px; + font-size: 11pt; + padding: 0px; + margin: 0px; + border-left-color: transparent; + border-right-color: transparent; + border-top-color: transparent; } QAbstractScrollArea { background-color: #19232D; @@ -94,141 +121,183 @@ QAbstractScrollArea:disabled { color: #9DA9B5; } -QScrollArea QWidget QWidget:disabled { - background-color: #19232D; +QCheckBox { + color: #fff; + padding: 4px; + font-size: 12pt; + border-color: transparent; } -QScrollBar:horizontal { - height: 16px; - margin: 2px 16px 2px 16px; - border: 1px solid #455364; - border-radius: 4px; - background-color: #19232D; +QCheckBox:disabled { + color: #808086; + padding: 6px; } -QScrollBar:vertical { - background-color: #19232D; - width: 16px; - margin: 16px 2px 16px 2px; - border: 1px solid #455364; - border-radius: 4px; +QCheckBox::indicator:checked { + height: 13px; + width: 13px; + border-style:solid; + border-width: 2px; + border-color: #e67e22; + color: #a9b7c6; + background-color: #d63d12; } -QScrollBar::handle:horizontal { - background-color: #60798B; - border: 1px solid #455364; - border-radius: 4px; - min-width: 8px; +QCheckBox::indicator:unchecked { + height: 11px; + width: 11px; + border-style:solid; + border-width: 2px; + border-color: #e67e22; + color: #a9b7c6; + background-color: transparent; } -QScrollBar::handle:horizontal:hover { - background-color: #346792; - border: #346792; - border-radius: 4px; - min-width: 8px; +QComboBox { + border: 2px solid #f73; + padding: 1px; + font-size: 10pt; + min-width: 2em; } -QScrollBar::handle:horizontal:focus { - border: 1px solid #1A72BB; +QComboBox:on { + padding-top: 3px; + padding-left: 4px; } -QScrollBar::handle:vertical { - background-color: #60798B; - border: 1px solid #455364; - min-height: 8px; - border-radius: 4px; +QComboBox::drop-down { + width: 20px; + background: #555; + padding: 1px 1px 1px 1px; + border-left-width: 2px; + border-left-color: #311; + border-left-style: outset; } -QScrollBar::handle:vertical:hover { - background-color: #346792; - border: #346792; - border-radius: 4px; - min-height: 8px; +QComboBox::down-arrow:on { + top: 1px; } -QScrollBar::handle:vertical:focus { - border: 1px solid #1A72BB; +QComboBox QAbstractItemView { + border: 1px solid #444; + selection-background-color: lightgray; } -QScrollBar::add-line:horizontal { - margin: 0px 0px 0px 0px; - height: 12px; - width: 12px; - subcontrol-position: right; - subcontrol-origin: margin; +QComboBox::down-arrow { + image: url(%s); } -QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { - height: 12px; - width: 12px; - subcontrol-position: right; - subcontrol-origin: margin; +QDialog { + background-color:#000000; } -QScrollBar::add-line:vertical { - margin: 3px 0px 3px 0px; - height: 12px; - width: 12px; - subcontrol-position: bottom; - subcontrol-origin: margin; +QGroupBox { + border-style: dashed; + border-width: 2px; + border-color: #841; + margin: 8px; + padding: 8px; + border-radius: 12px; + font-size: 15px; + font-weight: bold; } -QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { - height: 12px; - width: 12px; - subcontrol-position: bottom; - subcontrol-origin: margin; +QHeaderView::section { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, + y2: 1, stop:0 #54585b, stop:1 #393c3e); + color: #CFF; + padding: 1px 2px 1px 4px; + border: 1px solid #323232; + border-top-width: 0; + font-size: 12pt; + font-weight: bold; + border-left-color: #5e6163; + border-right-color: #2a2c2d; } -QScrollBar::sub-line:horizontal { - margin: 0px 3px 0px 3px; - height: 12px; - width: 12px; - subcontrol-position: left; - subcontrol-origin: margin; +QHeaderView::section:hover { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, + y2: 1, stop:0 #64686b, stop:1 #494c4e); + border-bottom-color: #424242; } -QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { - height: 12px; - width: 12px; - subcontrol-position: left; - subcontrol-origin: margin; +QHeaderView::section:first { + border-left-width: 0; } -QScrollBar::sub-line:vertical { - margin: 3px 0px 3px 0px; - height: 12px; - width: 12px; - subcontrol-position: top; - subcontrol-origin: margin; +QHeaderView::section:last { + border-right-width: 0; } -QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { - height: 12px; - width: 12px; - subcontrol-position: top; - subcontrol-origin: margin; +QHeaderView::section:checked { + color: #fff; + background-color: #222; } -QTabWidget::pane { - border-top: 2px solid black; - font-size: 10pt; +QLabel, +QLabel:disabled { + border-width: 1px; + background-color: transparent; + padding: 0px; + font-size: 8pt; + border-color: transparent; + selection-background-color: #2f4f4f; } -QTabWidget::tab-bar { - left: 5px; +QLineEdit { + padding: 4px; + border-width: 1px; + border-style: groove; + margin-top: 3px; + margin-bottom: 3px; + font-size: 9pt; + background-color: #19232D; } -QTabBar::tab { - border-style: outset; - border-color: #f61; - border-width: 3px; +QLabel { + padding: 2px; + padding-top: 4px; + padding-bottom: 4px; font-size: 10pt; - color: #e9e7e6; - padding-left: 8px; - padding-right: 8px; - margin-right: 2px; - padding-bottom: 2px; - background-color: #444; + font-weight: bold; } -QTabBar::tab:hover { - color: #ffffff; +QMainWindow::separator { + background: #000; + border-width: 0px; } -QTabBar::tab:selected, QTabBar::tab:last:selected { - border-color: #e76500; - font-style: bold; - border-width: 2px; - border-style: inset; - color: #ffffff; - padding-left: 8px; - padding-right: 8px; - padding-bottom: 0px; - margin-right: 2px; - background-color: #333; +QMainWindow::separator:hover { + background: transparent; } -QPushButton{ - margin-top: 3px; +QMenuBar { + background-color: #322; + padding: 2px; + font-size: 9pt; + margin-bottom: 2px; + border-bottom: 2px solid #555555; +} +QMenuBar::item:pressed { + background-color: #4b6eaf; +} +QMenuBar::item:selected:!pressed { + background-color: #585b5d; +} +QMenu { + border: 1px solid #2d2d2d; + font-size: 8pt; +} +QMenu::item:disabled { + color: #999999; +} +QMenu::item:selected { + background-color: #4b6eaf; +} +QMenu::icon { + border: 0px solid transparent; + background-color: transparent; +} +QMenu::icon:checked { + background-color: blue; + border: 1px inset red; + position: absolute; + top: 1px; + right: 1px; + bottom: 1px; + left: 1px; +} +QMenu::separator { + height: 2px; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, + y2: 1, stop:0 #282a2b, stop:1 #45484b); + margin: 0 1px; +} +QMenu::indicator { + width: 13px; + height: 13px; + background-color: blue; +} +QPushButton{ + margin-top: 3px; margin-bottom: 3px; margin-left: 8px; margin-right: 8px; @@ -239,8 +308,7 @@ border-bottom-color: #e67e22; border-radius: 8px; border-width: 3px; - padding-top: 4px; - padding-bottom: 4px; + padding: 3px 4px 3px 4px; font-size: 12pt; font-weight: bold; color: #dedede; @@ -266,23 +334,6 @@ padding-bottom: 1px; background-color: #444; } -QToolButton { - font-size: 10pt; - border-style: outset; - border-color: #e67e22; - border-width: 3px; - border-radius: 8px; - color: #FFF; - padding: 5px; - padding-top: 3px; - background-color: #112; -} -QToolButton:hover { - border-style: inset; - margin-bottom: 1px; - padding: 4px; - background-color: #000; -} QRadioButton { background-color: transparent; font-size: 12pt; @@ -313,33 +364,147 @@ width: 13px; height: 13px; } -QCheckBox { - color: #fff; - padding: 4px; - font-size: 12pt; - border-color: transparent; +QScrollArea QWidget QWidget:disabled { + background-color: #19232D; } -QCheckBox:disabled { - color: #808086; - padding: 6px; +QScrollBar:horizontal { + height: 16px; + margin: 2px 16px 2px 16px; + border: 1px solid #455364; + border-radius: 4px; + background-color: #19232D; } -QCheckBox::indicator:checked { - height: 13px; - width: 13px; - border-style:solid; - border-width: 2px; - border-color: #e67e22; - color: #a9b7c6; - background-color: #d63d12; +QScrollBar:vertical { + background-color: #19232D; + width: 16px; + margin: 16px 2px 16px 2px; + border: 1px solid #455364; + border-radius: 4px; } -QCheckBox::indicator:unchecked { - height: 11px; - width: 11px; - border-style:solid; +QScrollBar::handle:horizontal { + background-color: #60798B; + border: 1px solid #455364; + border-radius: 4px; + min-width: 8px; +} +QScrollBar::handle:horizontal:hover { + background-color: #346792; + border: #346792; + border-radius: 4px; + min-width: 8px; +} +QScrollBar::handle:horizontal:focus { + border: 1px solid #1A72BB; +} +QScrollBar::handle:vertical { + background-color: #60798B; + border: 1px solid #455364; + min-height: 8px; + border-radius: 4px; +} +QScrollBar::handle:vertical:hover { + background-color: #346792; + border: #346792; + border-radius: 4px; + min-height: 8px; +} +QScrollBar::handle:vertical:focus { + border: 1px solid #1A72BB; +} +QScrollBar::add-line:horizontal { + margin: 0px 0px 0px 0px; + height: 12px; + width: 12px; + subcontrol-position: right; + subcontrol-origin: margin; +} +QScrollBar::add-line:horizontal:hover, +QScrollBar::add-line:horizontal:on { + height: 12px; + width: 12px; + subcontrol-position: right; + subcontrol-origin: margin; +} +QScrollBar::add-line:vertical { + margin: 3px 0px 3px 0px; + height: 12px; + width: 12px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} +QScrollBar::add-line:vertical:hover, +QScrollBar::add-line:vertical:on { + height: 12px; + width: 12px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} +QScrollBar::sub-line:horizontal { + margin: 0px 3px 0px 3px; + height: 12px; + width: 12px; + subcontrol-position: left; + subcontrol-origin: margin; +} +QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { + height: 12px; + width: 12px; + subcontrol-position: left; + subcontrol-origin: margin; +} +QScrollBar::sub-line:vertical { + margin: 3px 0px 3px 0px; + height: 12px; + width: 12px; + subcontrol-position: top; + subcontrol-origin: margin; +} +QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { + height: 12px; + width: 12px; + subcontrol-position: top; + subcontrol-origin: margin; +} +QStatusBar { + border-top-color: black; + border-top-width: 1px; + padding: 3px; + font-size: 8pt; + color: #F00; +} +QTabWidget::pane { + border-top: 2px solid black; + font-size: 10pt; +} +QTabWidget::tab-bar { + left: 5px; +} +QTabBar::tab { + border-style: outset; + border-color: #f61; + border-width: 3px; + font-size: 10pt; + color: #e9e7e6; + padding-left: 8px; + padding-right: 8px; + margin-right: 2px; + padding-bottom: 2px; + background-color: #444; +} +QTabBar::tab:hover { + color: #ffffff; +} +QTabBar::tab:selected, QTabBar::tab:last:selected { + border-color: #e76500; + font-style: bold; border-width: 2px; - border-color: #e67e22; - color: #a9b7c6; - background-color: transparent; + border-style: inset; + color: #ffffff; + padding-left: 8px; + padding-right: 8px; + padding-bottom: 0px; + margin-right: 2px; + background-color: #333; } QTreeWidget { border: 1px solid #f61; @@ -349,11 +514,10 @@ } QTreeWidget::item::selected { color: #FFFFFF; - font-size: 10pt; + font-size: 9pt; border-color: transparent; } QTreeWidget::item::hover { - font-size: 9pt; color: #CFF8DC; border-color: transparent; } @@ -365,15 +529,6 @@ background-color: #ffffff; border: 1px solid #536D79; } -QTreeWidget QHeaderView::section { - background-color: black; - color: white; -} -QTreeWidget QHeaderView::section { - border: 1px solid #e57e22; - background-color: black; - color: white; -} QTreeWidget QProgressBar { color: black; background-color: #7a7a7a; @@ -410,177 +565,39 @@ } QTableWidget::item:hover { background-color: #7c7d7b; - border: dotted #ded 1px; + border: dotted #ded 2px; } QTableWidget QTableCornerButton::section{ background-color: black; border: 2px brown solid; } -QHeaderView::section { - background-color: qlineargradient(x1: 0, y1: 0, x2: 0, - y2: 1, stop:0 #54585b, stop:1 #393c3e); - color: #bbbbbb; - padding: 1px 2px 1px 4px; - border: 1px solid #323232; - border-top-width: 0; - font-size: 12pt; - font-weight: bold; - border-left-color: #5e6163; - border-right-color: #2a2c2d; +QToolBar { + spacing: 6px; } -QHeaderView::section:hover { - background-color: qlineargradient(x1: 0, y1: 0, x2: 0, - y2: 1, stop:0 #64686b, stop:1 #494c4e); - border-bottom-color: #424242; +QToolButton { + font-size: 8pt; + border-style: outset; + border-color: #e67e22; + border-width: 2px; + border-radius: 8px; + color: #FFF; + padding: 2px; + margin: 2px; + background-color: #112; } -QHeaderView::section:first { - border-left-width: 0; -} -QHeaderView::section:last { - border-right-width: 0; -} -QHeaderView::section:checked { - color: #fff; - background-color: #222; -} -QMenuBar { - background-color: #322; - padding: 2px; - font-size: 9pt; - margin-bottom: 2px; - border-bottom: 2px solid #555555; -} -QMenuBar::item:pressed { - background-color: #4b6eaf; -} -QMenuBar::item:selected:!pressed { - background-color: #585b5d; -} -QMenu { - border: 1px solid #2d2d2d; - font-size: 8pt; -} -QMenu::item:disabled { - color: #999999; -} -QMenu::item:selected { - background-color: #4b6eaf; -} -QMenu::icon { - border: 0px solid transparent; - background-color: transparent; -} -QMenu::icon:checked { - background-color: blue; - border: 1px inset red; - position: absolute; - top: 1px; - right: 1px; - bottom: 1px; - left: 1px; -} -QMenu::separator { - height: 2px; - background-color: qlineargradient(x1: 0, y1: 0, x2: 0, - y2: 1, stop:0 #282a2b, stop:1 #45484b); - margin: 0 1px; -} -QMenu::indicator { - width: 13px; - height: 13px; - background-color: blue; -} -QDialog { - background-color:#000000; -} -QLineEdit { - padding: 4px; - border-width: 1px; - border-style: groove; - margin-top: 3px; - margin-bottom: 3px; - font-size: 9pt; - background-color: #19232D; -} -QLabel { - padding: 2px; - padding-top: 4px; - padding-bottom: 4px; - font-size: 10pt; - font-weight: bold; -} -QStatusBar { - border: 2px groove black; - font-size: 8pt; - color: #F00; -} -QComboBox { - border: 2px solid #f73; - padding: 1px 1px 1px 3px; - font-size: 10pt; - min-width: 2em; -} -QComboBox:on { - padding-top: 3px; - padding-left: 4px; -} -QComboBox::drop-down { - width: 20px; - background: #555; - padding: 0px 2px 0px 2px; - border-left-width: 2px; - border-left-color: #311; - border-left-style: outset; -} -QComboBox::down-arrow:on { - top: 1px; -} -*[createButton="true"] { - padding: 3px; - margin: 0px; - font-size: 9pt; -} -*[editLine="true"] { - padding: 0px; - margin: 0px; - padding: 0px; - font-size: 9pt; -} -*[editCombo="true"] { - font-size: 12pt; - margin: 0px 0px 0px 0px; - border-width: 1px; - padding: 0px 0px 0px 0px; - min-height: 19px; -} -*[editButton="true"] { - margin: 2px; +QToolButton:hover { + border-style: inset; + margin-bottom: 1px; padding: 2px; - font-size: 11pt; - border-radius: 12px; -} -*[infoLine="true"] { - background-color: transparent; - color: #FFF; - border-radius: 0px; - border-width: 2px; - font-size: 11pt; - padding: 0px; - margin: 0px; - border-left-color: transparent; - border-right-color: transparent; - border-top-color: transparent; -} -QComboBox QAbstractItemView { - border: 1px solid #444; - selection-background-color: lightgray; + background-color: #000; } -QComboBox::down-arrow { - image: url(%s); +QWidget { + background-color: #39434d; + border-width: 0px; } -""" % path2url(str(arrow)) +""" % arrow) -light_theme = """ +light_theme = (""" * { background-color: #E3E6F1; color: #000000; @@ -621,28 +638,54 @@ border-color: #0CF; selection-background-color: #a6595b; } -QLabel, -QLabel:disabled { - border-width: 1px; - background-color: transparent; +*[editToolBar="true"] { + background-color: #3a3a3a; + spacing: 3px; +} +*[editToolBar="true"] QComboBox { + background-color: #3cc; + margin-left: 6px; + border: 1px inset #5b310b; + border-radius: 4px; + font-size: 9pt; + padding: 3px; +} +*[editToolBar="true"] QComboBox QLineEdit { + margin: 0px; padding: 0px; - font-size: 8pt; - border-color: transparent; - selection-background-color: #ccc; } -QMainWindow::separator { - background: #0114fe; - border-width: 0px; +*[createButton="true"] { + padding: 3px; + font-size: 9pt; + margin: 0px; } -QMainWindow::separator:hover { - background: transparent; +*[editCombo="true"] { + margin: 0px 0px 0px 0px; + font-size: 12pt; + border-width: 1px; + padding: 0px 0px 0px 0px; + min-height: 19px; } -QWidget { - background-color: #E3E6F1; - border-width: 0px; +*[editButton="true"] { + margin: 2px; + padding: 2px; + font-size: 10pt; + border-radius: 12px; +} +*[infoLine="true"] { + background-color: transparent; + color: #000; + font-size: 11pt; + border-radius: 0px; + border-width: 2px; + padding: 0px; + margin: 0px; + border-left-color: transparent; + border-right-color: transparent; + border-top-color: transparent; } QAbstractScrollArea { - background-color: #CFC; + background-color: #E3E6F1; border: 1px solid #0CF; border-radius: 4px; padding: 2px; @@ -651,51 +694,299 @@ QAbstractScrollArea:disabled { color: #E3E6F1; } -QScrollArea QWidget QWidget:disabled { - background-color: #E3E6F1; +QCheckBox { + color: #000; + padding: 4px; + font-size: 12pt; + border-color: transparent; } -QScrollBar:horizontal { - height: 16px; - margin: 2px 16px 2px 16px; - border: 1px solid #ffc977; - border-radius: 4px; - background-color: #001c46; +QCheckBox:disabled { + color: #808086; + font-size: 9pt; + padding: 6px; } -QScrollBar:vertical { - background-color: #25b511; - width: 16px; - margin: 16px 2px 16px 2px; - border: 1px solid #eae64d; - border-radius: 4px; +QCheckBox::indicator:checked { + height: 13px; + width: 13px; + border-style: solid; + border-width: 2px; + border-color: #F41; + color: #000; + background-color: #FAEFEE; } -QScrollBar::handle:horizontal { - background-color: #888; - border: 1px solid #836727; - border-radius: 4px; - min-width: 8px; +QCheckBox::indicator:unchecked { + height: 11px; + width: 11px; + border-style: solid; + border-width: 2px; + border-color: #F41; + color: #000; + background-color: transparent; } -QScrollBar::handle:horizontal:hover { - background-color: #665997; - border: #f9f046; - border-radius: 4px; - min-width: 8px; +QComboBox QAbstractItemView { + border: 1px solid #DFF; + selection-background-color: lightgray; } -QScrollBar::handle:horizontal:focus { - border: 1px solid #1A72BB; +QComboBox::down-arrow { + image: url(%s); } -QScrollBar::handle:vertical { - background-color: #336; - border: 1px solid #eaf74a; - min-height: 8px; - border-radius: 4px; +QComboBox::down-arrow:on { + top: 1px; + background-color: #555; } -QScrollBar::handle:vertical:hover { - background-color: #ffffff; - border: #eae41a; - border-radius: 4px; - min-height: 8px; +QComboBox { + border: 2px solid #F41; + background-color: #3EC; + font-size: 10pt; + padding: 1px; + min-width: 2em; } -QScrollBar::handle:vertical:focus { +QComboBox:on { + padding-top: 3px; + padding-left: 4px; +} +QComboBox::drop-down { + width: 20px; + background: #0EE; + padding: 1px; + border-left-width: 2px; + border-left-color: #449; + border-left-style: outset; +} +QDialog { + background-color: #CFE; +} +QGroupBox { + border-style: dashed; + border-width: 2px; + border-color: #CCF; + margin: 8px; + padding: 8px; + border-radius: 12px; + font-size: 15px; + font-weight: bold; +} +QHeaderView::section { + background-color: qlineargradient( + x1: 0, y1: 0, x2: 0, y2: 1, stop:0 #719bfd:1 #88d9ff); + color: #001111; + font-size: 12pt; + border: 1px solid #3cc; + border-top-width: 0; + border-left-color: #5e6163; + border-right-color: #2a2c2d; +} +QHeaderView::section:hover { + background-color: qlineargradient( + x1: 0, y1: 0, x2: 0, y2: 1, stop:0 #77AFFF, stop:1 #99dcee); + border-bottom-color: #AFF; +} +QHeaderView::section:first { + border-left-width: 0; +} +QHeaderView::section:last { + border-right-width: 0; +} +QHeaderView::section:checked { + color: #000; + background-color: #AFF; +} +QLineEdit { + padding: 4px; + border-width: 1px; + border-style: groove; + margin-top: 3px; + margin-bottom: 3px; + font-size: 9pt; + background-color: #E3E6F1; +} +QLineEdit::read-only { + background-color: #CFC; +} +QLabel { + padding: 2px; + padding-top: 4px; + padding-bottom: 4px; + font-size: 10pt; + font-weight: bold; +} +QLabel, +QLabel:disabled { + border-width: 1px; + background-color: transparent; + padding: 0px; + font-size: 8pt; + border-color: transparent; + selection-background-color: #ccc; +} +QMenuBar { + background-color: #CFF; + font-size: 9pt; + padding: 2px; + margin-bottom: 2px; + border-bottom: 2px solid #555555; +} +QMenuBar::item:pressed { + background-color: #4b6eaf; +} +QMenuBar::item:selected:!pressed { + background-color: #585b5d; +} +QMenu { + font-size: 8pt; + border: 1px solid #2d2d2d; +} +QMenu::item:disabled { + color: #999999; +} +QMenu::item:selected { + background-color: #4b9eCf; +} +QMenu::icon { + border: 0px solid transparent; + background-color: transparent; +} +QMenu::icon:checked { + background-color: #AFF; + border: 1px inset red; + position: absolute; + top: 1px; + right: 1px; + bottom: 1px; + left: 1px; +} +QMenu::separator { + height: 2px; + background-color: qlineargradient( + x1: 0, y1: 0, x2: 0, y2: 1, stop:0 #282a2b, stop:1 #45484b); + margin: 0 1px; +} +QMenu::indicator { + width: 13px; + height: 13px; + background-color: #F55; +} +QMainWindow::separator { + background: #0114fe; + border-width: 0px; +} +QMainWindow::separator:hover { + background: transparent; +} +QPushButton{ + margin-top: 3px; + margin-bottom: 3px; + margin-left: 8px; + margin-right: 8px; + border-style: outset; + border-top-color: #E66; + border-right-color: #F55; + border-left-color: #F43; + border-bottom-color: #F41; + border-radius: 6px; + border-width: 3px; + padding-top: 4px; + font-size: 12pt; + padding-bottom: 4px; + font-weight: bold; + color: #000000; + background-color: #8eC2fd; +} +QPushButton:hover{ + border-style: inset; + border-width: 3px; + color: #6b3232; + background-color: #5bc6f9; +} +QPushButton:pressed { + border-style: inset; + border-bottom-width: 3px; + color: #482622; + background-color: #d0f5fd; +} +QPushButton:disabled { + border-style: solid; + border-bottom-width: 1px; + border-style: solid; + color: #011; + padding-bottom: 1px; + background-color: #CCC; +} +QRadioButton { + background-color: transparent; + border: transparent; + padding-top: 2px; + font-size: 12pt; + margin-top: 2px; + margin-bottom: 2px; + padding-bottom: 4px; + color: #005; +} +QRadioButton::indicator::unchecked { + border: 2px inset #333; + border-radius: 6px; + background-color: #ffe006; + width: 13px; + height: 13px; +} +QRadioButton::indicator::unchecked:hover { + border-radius: 5px; + background-color: #fdfd00; + width: 13px; + height: 13px; +} +QRadioButton::indicator::checked { + border: 2px inset #8e5740; + border-radius: 4px; + background-color: #f00; + width: 13px; + height: 13px; +} +QScrollArea QWidget QWidget:disabled { + background-color: #E3E6F1; +} +QScrollBar:horizontal { + height: 16px; + margin: 2px 16px 2px 16px; + border: 1px solid #EA7; + border-radius: 4px; + background-color: #25b511; +} +QScrollBar:vertical { + background-color: #25b511; + width: 16px; + margin: 16px 2px 16px 2px; + border: 1px solid #EA7; + border-radius: 4px; +} +QScrollBar::handle:horizontal { + background-color: #AE7; + border: 1px solid #EA7; + border-radius: 4px; + min-width: 8px; +} +QScrollBar::handle:horizontal:hover { + background-color: #665997; + border: #553997; + border-radius: 4px; + min-width: 8px; +} +QScrollBar::handle:horizontal:focus { + border: 1px solid #1A72BB; +} +QScrollBar::handle:vertical { + background-color: #AE7; + border: 1px solid #EA7; + min-height: 8px; + border-radius: 4px; +} +QScrollBar::handle:vertical:hover { + background-color: #665997; + border: #553997; + border-radius: 4px; + min-height: 8px; +} +QScrollBar::handle:vertical:focus { border: 1px solid #1A72BB; } QScrollBar::add-line:horizontal { @@ -754,6 +1045,13 @@ subcontrol-position: top; subcontrol-origin: margin; } +QStatusBar { + border-top-color: black; + border-top-width: 1px; + font-size: 8pt; + padding: 3px; + color: #700; +} QTabWidget::pane { border-top-color: #667; border-top-width: 2px; @@ -768,7 +1066,7 @@ } QTabBar::tab { border-style: outset; - border-color: #84378a; + border-color: #AFF; border-width: 3px; color: #000000; font-size: 10pt; @@ -783,7 +1081,7 @@ color: #002288; } QTabBar::tab:selected, QTabBar::tab:last:selected { - border-color: #883e00; + border-color: #AFF; border-bottom-color: transparent; font-style: bold; border-width: 2px; @@ -797,123 +1095,50 @@ margin-bottom: -3px; background-color: #E3E6F1; } -QPushButton{ - margin-top: 3px; - margin-bottom: 3px; - margin-left: 8px; - margin-right: 8px; - border-style: outset; - border-top-color: #9b5317; - border-right-color: #572c0b; - border-left-color: #9f4f13; - border-bottom-color: #5b310b; - border-radius: 6px; - border-width: 3px; - padding-top: 4px; - font-size: 12pt; - padding-bottom: 4px; - font-weight: bold; - color: #000000; - background-color: #8ea2fd; +QTableWidget { + color: #000; + font-size: 11pt; + border-color: #8FF; + border-width: 2px; + border-style: ridge; + border-radius: 4px; + margin: 10px; + selection-background-color: #F0AFA3; + gridline-color: #ac4a02; } -QPushButton:hover{ - border-style: inset; - border-width: 3px; - color: #6b3232; - background-color: #5bc6f9; +QTableWidget::item:selected:hover { + background-color: #E66; } -QPushButton:pressed { - border-style: inset; - border-bottom-width: 3px; - color: #482622; - background-color: #d0f5fd; +QTableWidget::item:hover { + background-color: #CFF; + border: dotted #ded 2px; } -QPushButton:disabled { - border-style: solid; - border-bottom-width: 1px; - border-style: solid; - color: #011; - padding-bottom: 1px; - background-color: #DFF; +QTableWidget QTableCornerButton::section{ + background-color: black; + border: 2px brown solid; +} +QToolBar { + spacing: 6px; } QToolButton { border-style: outset; - font-size: 10pt; + font-size: 8pt; border-color: #111; border-width: 3px; border-radius: 8px; color: #000; - padding: 5px; - padding-top: 3px; + padding: 2px; + margin: 2px; background-color: #8ea2fd; } QToolButton:hover { border-style: inset; margin-bottom: 1px; - padding: 4px; + padding: 2px; background-color: #5bc6f9; } -QRadioButton { - background-color: transparent; - border: transparent; - padding-top: 2px; - font-size: 12pt; - margin-top: 2px; - margin-bottom: 2px; - padding-bottom: 4px; - color: #005; -} -QRadioButton::indicator::unchecked { - border: 2px inset #333; - border-radius: 6px; - background-color: #ffe006; - width: 13px; - height: 13px; -} -QRadioButton::indicator::unchecked:hover { - border-radius: 5px; - background-color: #fdfd00; - width: 13px; - height: 13px; -} -QRadioButton::indicator::checked { - border: 2px inset #8e5740; - border-radius: 4px; - background-color: #f00; - width: 13px; - height: 13px; -} -QCheckBox { - color: #000; - padding: 4px; - font-size: 12pt; - border-color: transparent; -} -QCheckBox:disabled { - color: #808086; - font-size: 9pt; - padding: 6px; -} -QCheckBox::indicator:checked { - height: 13px; - width: 13px; - border-style: solid; - border-width: 2px; - border-color: #111; - color: #a9b7c6; - background-color: #d63d12; -} -QCheckBox::indicator:unchecked { - height: 11px; - width: 11px; - border-style: solid; - border-width: 2px; - border-color: #111; - color: #a9b7c6; - background-color: transparent; -} QTreeWidget { - border: 1px solid #f61; + border: 1px solid #ACF; background-color: #cbfefc; font-size: 9pt; color: #000; @@ -924,25 +1149,16 @@ border-color: transparent; } QTreeWidget::item::hover { - color: #CFF8DC; + color: #3F3833; border-color: transparent; } QTreeWidget::indicator::checked { background-color: #000000; - border: 1px solid #536D79; + border: 1px solid #EC9; } QTreeWidget::indicator::unchecked { background-color: #000000; - border: 1px solid #536D79; -} -QTreeWidget QHeaderView::section { - background-color: #ffffff; - color: #000; -} -QTreeWidget QHeaderView::section { - border: 1px solid #027740; - background-color: #fff; - color: #000; + border: 1px solid #EC9; } QTreeWidget QProgressBar { color: black; @@ -963,195 +1179,8 @@ border-radius: 3px; width: 16px; } -QTableWidget { - color: #000; - font-size: 11pt; - border-color: #f71; - border-width: 2px; - border-style: ridge; - border-radius: 4px; - margin: 10px; - selection-background-color: #3a3a3a; - gridline-color: #ac4a02; -} -QTableWidget::item:selected:hover { - background-color: #7c7d7b; -} -QTableWidget::item:hover { - background-color: #7c7d7b; - border: dotted #ded 1px; -} -QTableWidget QTableCornerButton::section{ - background-color: black; - border: 2px brown solid; -} -QHeaderView::section { - background-color: qlineargradient( - x1: 0, y1: 0, x2: 0, y2: 1, stop:0 #719bfd:1 #88d9ff); - color: #001111; - font-size: 12pt; - border: 1px solid #67fe56; - border-top-width: 0; - border-left-color: #5e6163; - border-right-color: #2a2c2d; -} -QHeaderView::section:hover { - background-color: qlineargradient( - x1: 0, y1: 0, x2: 0, y2: 1, stop:0 #64686b, stop:1 #494c4e); - border-bottom-color: #424242; -} -QHeaderView::section:first { - border-left-width: 0; -} -QHeaderView::section:last { - border-right-width: 0; -} -QHeaderView::section:checked { - color: #000; - background-color: #AFF; -} -QMenuBar { - background-color: #CFF; - font-size: 9pt; - padding: 2px; - margin-bottom: 2px; - border-bottom: 2px solid #555555; -} -QMenuBar::item:pressed { - background-color: #4b6eaf; -} -QMenuBar::item:selected:!pressed { - background-color: #585b5d; -} -QMenu { - font-size: 8pt; - border: 1px solid #2d2d2d; -} -QMenu::item:disabled { - color: #999999; -} -QMenu::item:selected { - background-color: #4b6eaf; -} -QMenu::icon { - border: 0px solid transparent; - background-color: transparent; -} -QMenu::icon:checked { - background-color: #AFF; - border: 1px inset red; - position: absolute; - top: 1px; - right: 1px; - bottom: 1px; - left: 1px; -} -QMenu::separator { - height: 2px; - background-color: qlineargradient( - x1: 0, y1: 0, x2: 0, y2: 1, stop:0 #282a2b, stop:1 #45484b); - margin: 0 1px; -} -QMenu::indicator { - width: 13px; - height: 13px; - background-color: #FAA; -} -QDialog { - background-color: #CFE; -} -QLineEdit { - padding: 4px; - border-width: 1px; - border-style: groove; - margin-top: 3px; - margin-bottom: 3px; - font-size: 9pt; - background-color: #CFC; -} -QLineEdit::read-only { - background-color: #CFC; -} -QLabel { - padding: 2px; - padding-top: 4px; - padding-bottom: 4px; - font-size: 10pt; - font-weight: bold; -} -QStatusBar { - border: 1px groove #6f3375; - background-color: #222; - color: #F00; - font-size: 8pt; - border-radius: 3px; - padding: 3px; -} - -QComboBox { - border: 2px solid #645a3c; - background-color: #0EE; - font-size: 10pt; - padding: 1px 1px 1px 3px; - min-width: 2em; -} -QComboBox:on { - padding-top: 3px; - padding-left: 4px; -} -QComboBox::drop-down { - width: 20px; - background: #0EE; - padding: 0px 2px 0px 2px; - border-left-width: 2px; - border-left-color: #449; - border-left-style: outset; -} -QComboBox::down-arrow:on { - top: 1px; - background-color: #555; -} -*[createButton="true"] { - padding: 3px; - font-size: 9pt; - margin: 0px; - } -*[editLine="true"] { - padding: 0px; - font-size: 9pt; - margin: 0px; - padding: 0px; -} -*[editCombo="true"] { - margin: 0px 0px 0px 0px; - font-size: 12pt; - border-width: 1px; - padding: 0px 0px 0px 0px; - min-height: 19px; -} -*[editButton="true"] { - margin: 2px; - padding: 2px; - font-size: 11pt; - border-radius: 12px; -} -*[infoLine="true"] { - background-color: transparent; - color: #000; - font-size: 11pt; - border-radius: 0px; - border-width: 2px; - padding: 0px; - margin: 0px; - border-left-color: transparent; - border-right-color: transparent; - border-top-color: transparent; -} -QComboBox QAbstractItemView { - border: 1px solid #DFF; - selection-background-color: lightgray; -} -QComboBox::down-arrow { - image: url(%s); +QWidget { + background-color: #E3E6F1; + border-width: 0px; } -""" % path2url(str(arrow)) +""" % arrow) diff --git a/torrentfileQt/toolTab.py b/torrentfileQt/toolTab.py new file mode 100644 index 0000000..bf9246b --- /dev/null +++ b/torrentfileQt/toolTab.py @@ -0,0 +1,316 @@ +#! /usr/bin/python3 +# -*- coding: utf-8 -*- + +############################################################################## +# Copyright 2020 AlexPDev +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################## +"""Magnet Widget containing Testing creation of Magnet URIs.""" + +import os + +from PySide6.QtCore import Qt +from PySide6.QtGui import QIcon +from PySide6.QtWidgets import (QComboBox, QGridLayout, QGroupBox, QHBoxLayout, + QLabel, QLineEdit, QPushButton, QVBoxLayout, + QWidget) +from torrentfile import magnet +from torrentfile.utils import path_stat + +from torrentfileQt.utils import (browse_files, browse_folder, browse_torrent, + get_icon) + + +class ToolWidget(QWidget): + """Tab for creating magnet URL's and downloading torrentfiles from them.""" + + def __init__(self, parent=None): + """Initialize the widget for creating magnet URI's from a metafile.""" + super().__init__(parent=parent) + self.window = parent.window + self.layout = QVBoxLayout() + self.setLayout(self.layout) + self.magnetgroup = MagnetGroup(self) + self.layout.addWidget(self.magnetgroup) + self.piece_length_calculator = PieceLengthCalculator() + self.layout.addWidget(self.piece_length_calculator) + + +class SubmitButton(QPushButton): + """Submit current information to be processed into a megnet URI.""" + + def __init__(self, parent=None): + """Initialize the button for magnet creation.""" + super().__init__(parent=parent) + self.widget = parent + self.window = parent.window + self.setText("Create Magnet") + self.clicked.connect(self.magnet) + + def magnet(self): + """Create a magnet URI from information contained in form.""" + fd = self.widget.pathEdit.text() + if os.path.exists(fd): + uri = magnet(fd) + self.widget.magnetEdit.setText(uri) + + +class MetafileButton(QPushButton): + """ + Find a .torrent file in native file browser button actions. + + Perameters + ---------- + parent : `QWidget` + This widgets parent. + """ + + def __init__(self, parent=None): + """Initialize the metafile button.""" + super().__init__(parent=parent) + self.window = parent.window + self.widget = parent + self.setText("Select Torrent File") + self.setIcon(QIcon(get_icon("browse_file"))) + self.setCursor(Qt.CursorShape.PointingHandCursor) + self.pressed.connect(self.select_metafile) + + def select_metafile(self, path=None): + """Find metafile in file browser.""" + if not path: + path = browse_torrent(self, path) # pragma: nocover + self.widget.pathEdit.setText(path if path else "") + + +class MagnetGroup(QGroupBox): + """ + Group Box for calculating magnet uri's. + + Paramters + --------- + parent : QWidget + the parent to this widget + """ + + def __init__(self, parent=None): + """Create the Magnet group box widget.""" + super().__init__(parent=parent) + self.layout = QVBoxLayout() + self.setTitle("Create Magnet URI") + self.setLayout(self.layout) + self.metafilebutton = MetafileButton(self) + self.submit_button = SubmitButton(self) + self.pathEdit = QLineEdit(self) + self.magnetEdit = QLineEdit(self) + for edit in [self.pathEdit, self.magnetEdit]: + edit.setProperty("infoLine", "true") + self.pathLabel = QLabel("Path: ") + self.magnetLabel = QLabel("Magnet URI: ") + self.grid = QGridLayout() + self.grid.addWidget(self.pathLabel, 0, 0, 1, 1) + self.grid.addWidget(self.pathEdit, 0, 1, 1, 1) + self.grid.addWidget(self.magnetLabel, 1, 0, 1, 1) + self.grid.addWidget(self.magnetEdit, 1, 1, 1, 1) + self.layout.addLayout(self.grid) + self.hlayout = QHBoxLayout() + self.hlayout.addWidget(self.metafilebutton) + self.hlayout.addWidget(self.submit_button) + self.layout.addLayout(self.hlayout) + self.setAcceptDrops(True) + + def dragEnterEvent(self, event): + """Drag enter event for widget.""" + if event.mimeData().hasUrls: + self.urls = event.mimeData().urls() + event.accept() + return True + return event.ignore() + + def dragMoveEvent(self, event): + """Drag Move Event for widgit.""" + if event.mimeData().hasUrls: + self.urls = event.mimeData().urls() + event.accept() + return True + return event.ignore() + + def dropEvent(self, evt): + """Drag drop event for widgit.""" + urls = evt.mimeData().urls() + loc = urls[0].toLocalFile() + if os.path.exists(loc): + self.pathEdit.setText(loc) + self.submit_button.click() + return True + return False + + +class PieceLengthBox(QComboBox): + """ + Combo box for the piece length options. + + Parameters + ---------- + parent : QWidget + the parent to this widget + """ + + def __init__(self, parent=None): + """Create the piece length combo box widget.""" + super().__init__(parent) + self.setEditable(False) + self.__data = {} + self.loadItems() + + def get_value(self): + """ + Get the current text's corresponding value. + """ + text = self.currentText() + return self.__data[text] + + def loadItems(self): + """ + Load the options into the list for selection. + """ + for i in range(14, 26): + value = 2**i + if i < 20: + text = f"{value // 2**10} KiB" + else: + text = f"{value // 2**20} MiB" + self.__data[text] = value + self.addItem(text) + + def set_item(self, value): + """ + Set the current text based on the value provided. + + Parameter + --------- + value : int + The value that matches the key text to select as current. + """ + self.blockSignals(True) + for k, v in self.__data.items(): + if v == value: + self.setCurrentText(k) + break + self.blockSignals(False) + + +class PieceLengthCalculator(QGroupBox): + """ + Group box for calculating ideal piece length. + + Parameters + ---------- + parent : QWidget + the parent to this widget + """ + + def __init__(self, parent=None): + """Create the piece length calculator widget.""" + super().__init__(parent=parent) + self.setTitle("Piece Length Calculator") + self.layout = QVBoxLayout(self) + icon = QIcon(get_icon("browse_file")) + icon2 = QIcon(get_icon("browse_folder")) + self.fileButton = QPushButton(icon, "Select File", self) + self.folderButton = QPushButton(icon2, "Select Folder", self) + self.hlayout = QHBoxLayout() + self.hlayout.addWidget(self.fileButton) + self.hlayout.addWidget(self.folderButton) + self.path_label = QLabel("Path: ", self) + self.path_line = QLineEdit(self) + self.size_label = QLabel("Size: ", self) + self.file_count_label = QLabel("File Count: ") + self.piece_length_label = QLabel("Piece Length: ", self) + self.piece_count_label = QLabel("Total Pieces: ", self) + self.file_count_line = QLineEdit() + self.size_line = QLineEdit() + self.piece_count_line = QLineEdit() + self.piece_length_combo = PieceLengthBox(self) + for line in [ + self.piece_length_combo, + self.piece_count_line, + self.path_line, + self.size_line, + self.file_count_line, + ]: + line.setProperty("infoLine", "true") + self.grid = QGridLayout() + self.grid.addWidget(self.path_label, 0, 0, 1, 1) + self.grid.addWidget(self.path_line, 0, 1, 1, 1) + self.grid.addWidget(self.size_label, 1, 0, 1, 1) + self.grid.addWidget(self.size_line, 1, 1, 1, 1) + self.grid.addWidget(self.piece_length_label, 2, 0, 1, 1) + self.grid.addWidget(self.piece_length_combo, 2, 1, 1, 1) + self.grid.addWidget(self.piece_count_label, 3, 0, 1, 1) + self.grid.addWidget(self.piece_count_line, 3, 1, 1, 1) + self.grid.addWidget(self.file_count_label, 4, 0, 1, 1) + self.grid.addWidget(self.file_count_line, 4, 1, 1, 1) + self.layout.addLayout(self.grid) + self.layout.addLayout(self.hlayout) + self.fileButton.clicked.connect(self.browse_files) + self.folderButton.clicked.connect(self.browse_folders) + self.piece_length_combo.currentTextChanged.connect( + self.calculate_piece_length) + + def calculate_piece_length(self): + """ + Calculate the piece length based on the current text of the combo box. + """ + size = self.size_line.text() + if size: + size = int(size) + plength = self.piece_length_combo.get_value() + val = size / plength + if int(val) == val: + self.piece_count_line.setText(str(int(val))) + else: # pragma: nocover + self.piece_count_line.setText(str(int(val + 1))) + + def calculate(self, path): + """ + Calculate all the fields based on the path selected by user. + + Parameters + ---------- + path : str + the path selected by the user by browsing the file system + """ + self.path_line.setText(path if path else "") + if path: + file_list, size, piece_length = path_stat(path) + self.piece_length_combo.set_item(piece_length) + self.size_line.setText(str(size)) + total_pieces = size / piece_length + if total_pieces == size // piece_length: + self.piece_count_line.setText(str(int(total_pieces))) + else: # pragma: nocover + self.piece_count_line.setText(str(int(total_pieces + 1))) + self.file_count_line.setText(str(len(file_list))) + + def browse_files(self, path=None): + """Browse for files for caluclating ideal piece lengths.""" + if not path: + path = browse_files(self) # pragma: nocover + self.calculate(path) + + def browse_folders(self, path=None): + """Browse for folders for calculating ideal piece lengths.""" + if not path: + path = browse_folder(self) # pragma: nocover + self.calculate(path) diff --git a/torrentfileQt/utils.py b/torrentfileQt/utils.py index 83a2002..4fc130c 100644 --- a/torrentfileQt/utils.py +++ b/torrentfileQt/utils.py @@ -124,6 +124,7 @@ def __init__(self): self.collection = [] self.line_num = 0 self.lines = [] + self.result = {} self.total = len(self.lines) def parse(self, sheet): diff --git a/torrentfileQt/window.py b/torrentfileQt/window.py index 42a328f..226a89b 100644 --- a/torrentfileQt/window.py +++ b/torrentfileQt/window.py @@ -28,9 +28,9 @@ from torrentfileQt.createTab import CreateWidget from torrentfileQt.editorTab import EditorWidget from torrentfileQt.infoTab import InfoWidget -from torrentfileQt.magnetTab import MagnetWidget from torrentfileQt.menu import MenuBar from torrentfileQt.qss import dark_theme, light_theme +from torrentfileQt.toolTab import ToolWidget from torrentfileQt.utils import StyleManager, get_icon THEMES = {"dark_theme": dark_theme, "light_theme": light_theme} @@ -101,13 +101,13 @@ def __init__(self, parent=None): self.checkWidget = CheckWidget(parent=self) self.infoWidget = InfoWidget(parent=self) self.editorWidget = EditorWidget(parent=self) - self.magnetWidget = MagnetWidget(parent=self) + self.toolWidget = ToolWidget(parent=self) self.addTab(self.createWidget, "Create Torrent") self.addTab(self.checkWidget, "Re-Check Torrent") self.addTab(self.infoWidget, "Torrent Info") self.addTab(self.editorWidget, "Torrent Editor") - self.addTab(self.magnetWidget, "Magnet URL") - self.magnetWidget.setObjectName("magnetWidget") + self.addTab(self.toolWidget, "Tools") + self.toolWidget.setObjectName("toolWidget") self.createWidget.setObjectName("createTab") self.checkWidget.setObjectName("checkTab") self.infoWidget.setObjectName("infoTab") @@ -147,4 +147,4 @@ def start(cls, args=None): # pragma: no cover def execute(): """Run application.""" - Application.start() + Application.start() # pragma: nocover diff --git a/tox.ini b/tox.ini index ce83f73..c88054f 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,8 @@ deps = PySide6 pyroma pytest-clarity + torrentfileQt + QStyler pytest-cov torrentfile bandit @@ -31,16 +33,16 @@ commands = pytest --cov=torrentfileQt --cov=tests --ff coverage xml coverage html - pydocstyle torrentfileQt tests - pycodestyle torrentfileQt tests - pylint torrentfileQt tests - bandit -r -c pyproject.toml torrentfileQt tests - pyroma . black torrentfileQt tests flake8 torrentfileQt tests yapf -r -i torrentfileQt tests autopep8 -r torrentfileQt tests isort torrentfileQt tests + pydocstyle torrentfileQt tests + pycodestyle torrentfileQt tests + pylint torrentfileQt tests + bandit -r -c pyproject.toml torrentfileQt tests + pyroma . [pydocstyle] ignore = D200, D210, D212, D213, D413, D407, D406, D203