123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- ########################################################################
- # Wiizard - A Wii games manager
- # Copyright (C) 2023 CYBERDEViL
- #
- # This file is part of Wiizard.
- #
- # Wiizard is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # Wiizard is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
- #
- ########################################################################
- from PyQt5.QtWidgets import (
- QApplication,
- QMainWindow,
- QMenuBar,
- QMenu,
- QWidget,
- QHBoxLayout,
- QComboBox,
- QSplitter,
- QSizePolicy,
- QStyle
- )
- from PyQt5.QtCore import (
- QCoreApplication,
- Qt,
- pyqtSignal,
- QSettings
- )
- import wiizard.globals as Global
- from wiizard.translations import _
- from wiizard.devices import DevicesModel as _DevicesModel
- from wiizard.thread import THREAD_FLAG_IS_CANCELLABLE, THREAD_FLAG_IS_STOPABLE
- from wiizard.models.source import _Sources
- from wiizard.views.source import SourceWidget
- from wiizard.views.about import AboutDialog
- from wiizard.views.operations import ApplyChangedDialog
- from wiizard.images import _SharedGameImages, AppResources
- from wiizard.const import (
- IMG_FRONT_COVER,
- IMG_FRONT_3D_COVER,
- IMG_DISC
- )
- from wiizard.views.images import DlImagesDialog
- from wiizard.views.settings import SettingsDialog
- from wiizard.models.settings import GameImageSettings
- from wiizard.views.manageLocalSources import ManageLocalWidget
- from wiizard.views.formatDialog import FormatDialog
- class SourcesView(QWidget):
- gamesUpdated = pyqtSignal() # Re-emit from any of the models
- def __init__(self, parent=None):
- QWidget.__init__(self, parent=parent)
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
- layout = QHBoxLayout(self)
- splitter = QSplitter(Qt.Horizontal, self)
- self.sourceA = SourceWidget(self)
- self.sourceB = SourceWidget(self)
- splitter.addWidget(self.sourceA)
- splitter.addWidget(self.sourceB)
- layout.addWidget(splitter)
- self.sourceA.listView.gamesUpdated.connect(self.gamesUpdated)
- self.sourceB.listView.gamesUpdated.connect(self.gamesUpdated)
- def getActiveModels(self):
- """ Returns current SourceModels used by either the left or the right view.
- """
- models = []
- sourceA = self.sourceA.listView.model()
- sourceB = self.sourceB.listView.model()
- if sourceA is not None:
- models.append(sourceA.sourceModel)
- if sourceB is not None:
- models.append(sourceB.sourceModel)
- return models
- class MainWindow(QMainWindow):
- def __init__(self, requestHandler, scraper):
- QMainWindow.__init__(self)
- AppResources.resolvePaths()
- self.setWindowIcon(AppResources.getIcon("wiizard_icon_32.png"))
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
- self.__requestHandler = requestHandler
- self.__scraper = scraper
- Global.SharedGameImages = _SharedGameImages()
- Global.DevicesModel = _DevicesModel()
- Global.DevicesModel.init()
- Global.Sources = _Sources()
- """ Menu bar """
- self.menubar = QMenuBar(self)
- # -- File menu --
- menufile = QMenu("File", self)
- menufile.addAction("Exit", self.__exit)
- menufile = QMenu(_("File"), self)
- menufile.addAction(_("Exit"), self.__exit)
- self.menubar.addMenu(menufile)
- # -- Settings --
- self.menubar.addAction(_("Settings"), self.__onSettingsClicked)
- # -- About --
- self.menubar.addAction(_("About"), self.__onAboutClicked)
- self.setMenuBar(self.menubar)
- """ Toolbar """
- toolbar = self.addToolBar(_("Toolbar"))
- self.dlMissingImgAction = toolbar.addAction(_("Download missing images"))
- self.dlMissingImgAction.setIcon(QApplication.style().standardIcon(QStyle.SP_ArrowDown))
- self.manageLocalAction = toolbar.addAction(_("Local source"))
- self.manageLocalAction.setToolTip(_("Manage local sources"))
- self.manageLocalAction.setIcon(QApplication.style().standardIcon(QStyle.SP_DirIcon))
- self.applyAction = toolbar.addAction(_("Apply"))
- self.applyAction.setToolTip(_("Apply changes"))
- self.applyAction.setIcon(QApplication.style().standardIcon(QStyle.SP_DialogApplyButton))
- self.applyAction.setEnabled(False)
- self.thumbSizeCombo = QComboBox(self)
- self.thumbSizeCombo.setToolTip(_("Icon size"))
- self.thumbSizeCombo.addItem(_("Large"))
- self.thumbSizeCombo.addItem(_("Medium"))
- self.thumbSizeCombo.addItem(_("Small"))
- self.thumbSizeCombo.setCurrentIndex(0)
- toolbar.addWidget(self.thumbSizeCombo)
- self.thumbTypeCombo = QComboBox(self)
- self.thumbTypeCombo.setToolTip(_("Icon type"))
- self.thumbTypeCombo.addItem(_("2D"))
- self.thumbTypeCombo.addItem(_("3D"))
- self.thumbTypeCombo.addItem(_("Disc"))
- self.thumbTypeCombo.addItem(_("None"))
- self.thumbTypeCombo.setCurrentIndex(1)
- toolbar.addWidget(self.thumbTypeCombo)
- self.formatAction = toolbar.addAction(_("Format"))
- self.formatAction.setIcon(QApplication.style().standardIcon(QStyle.SP_DialogResetButton))
- self.loadSettings()
- self.sourcesView = SourcesView(self)
- self.setCentralWidget(self.sourcesView)
- """ Make connections to signals """
- self.dlMissingImgAction.triggered.connect(self.dlMissingImgClicked)
- self.manageLocalAction.triggered.connect(self.manageLocal)
- self.applyAction.triggered.connect(self.onApply)
- self.thumbSizeCombo.currentIndexChanged.connect(self.onThumbSizeChange)
- self.thumbTypeCombo.currentIndexChanged.connect(self.onThumbTypeChange)
- self.sourcesView.gamesUpdated.connect(self.onGamesUpdated)
- self.formatAction.triggered.connect(self.__onFormatClicked)
- def __exit(self):
- QCoreApplication.exit(0)
- def __onAboutClicked(self):
- dialog = AboutDialog(parent=self)
- dialog.exec()
- def __onSettingsClicked(self):
- dialog = SettingsDialog(parent=self)
- dialog.exec()
- def closeEvent(self, event=None):
- # Disable everything.
- self.setEnabled(False)
- # Wait on threads
- for thread in Global.ActiveThreads:
- if (thread.flags & THREAD_FLAG_IS_CANCELLABLE):
- thread.cancel()
- elif (thread.flags & THREAD_FLAG_IS_STOPABLE):
- thread.stop()
- thread.wait()
- # Stop device monitoring thread
- Global.DevicesModel.stop()
- # Save settings
- self.saveSettings()
- def saveSettings(self):
- settings = QSettings("CYBERDEViL/Wiizard/", "config", self)
- settings.setValue("Sources", Global.Sources.serialize())
- settings.setValue("GameImageSettings", GameImageSettings.serialize())
- def loadSettings(self):
- settings = QSettings("CYBERDEViL/Wiizard/", "config", self)
- Global.Sources.deserialize(settings.value("Sources", dict(), dict))
- GameImageSettings.deserialize(settings.value("GameImageSettings",
- dict(), dict))
- def dlMissingImgClicked(self, checked=False):
- self.dlMissingImgAction.setEnabled(False)
- self.__dlMissingDialog = DlImagesDialog(self.__requestHandler, self.__scraper, parent=self)
- self.__dlMissingDialog.finished.connect(self.dlMissingImgClosed)
- self.__dlMissingDialog.show()
- def dlMissingImgClosed(self):
- self.__dlMissingDialog = None # dereference
- self.dlMissingImgAction.setEnabled(True)
- def manageLocal(self):
- dialog = ManageLocalWidget(parent=self)
- dialog.exec()
- def onThumbSizeChange(self, index):
- if index == 0 : # large
- Global.SharedGameImages.setImgSize(Global.SharedGameImages.SIZE_LARGE)
- elif index == 1: # medium
- Global.SharedGameImages.setImgSize(Global.SharedGameImages.SIZE_MEDIUM)
- elif index == 2: # small
- Global.SharedGameImages.setImgSize(Global.SharedGameImages.SIZE_SMALL)
- def onThumbTypeChange(self, index):
- if index == 0 : # 2D
- Global.SharedGameImages.setImgType(IMG_FRONT_COVER)
- elif index == 1: # 3D
- Global.SharedGameImages.setImgType(IMG_FRONT_3D_COVER)
- elif index == 2: # Disc
- Global.SharedGameImages.setImgType(IMG_DISC)
- else:
- Global.SharedGameImages.setImgType(None)
- def onGamesUpdated(self):
- """ One of the active sourceModels updated their games
- - update the apply button state """
- sourceModels = self.sourcesView.getActiveModels()
- for sourceModel in sourceModels:
- if sourceModel.hasPendingChanges():
- self.applyAction.setEnabled(True)
- return
- self.applyAction.setEnabled(False)
- def onApply(self):
- """ Apply button pressed """
- dialog = ApplyChangedDialog(self.sourcesView.getActiveModels(), parent=self)
- dialog.exec()
- def __onFormatClicked(self):
- dialog = FormatDialog(parent=self)
- dialog.exec()
|