def __init__(self, controller, cmd="", msg="", parent=None): """Init dropbox.""" super().__init__(parent) self.controller = controller self._instances.add(weakref.ref(self)) self.ident = len(self._instances) layout = QHBoxLayout() self.command = MonitoredLineEdit() if not cmd: cmd = '' self.command.setText(cmd) self.command.setAlignment(Qt.AlignCenter) self.command.setPlaceholderText(("!command")) layout.addWidget(self.command) self.message = MonitoredLineEdit() self.message.setText(msg) self.message.setAlignment(Qt.AlignCenter) self.message.setPlaceholderText(_('message, e.g.,') + ' (URL)') self.message.setToolTip( _('Available placeholders:') + ' ' + ', '.join(self.controller.placeholders.available())) completer = Completer(self.controller.placeholders.available(), self.message) self.message.setCompleter(completer) layout.addWidget(self.message) self.pushButton1 = QPushButton(_('Test')) self.pushButton1.clicked.connect( lambda: self.testPlaceholder(self.message.text())) layout.addWidget(self.pushButton1) self.pushButton2 = QPushButton(_('Delete')) self.pushButton2.clicked.connect(self.remove) layout.addWidget(self.pushButton2) self.setLayout(layout) for ref in self._instances: obj = ref() if obj is not None: obj.setTitle()
def _createView(self): layout = QVBoxLayout() self.le_league = MonitoredLineEdit() self.le_league.setText("League TBD") self.le_league.setAlignment(Qt.AlignCenter) self.le_league.setPlaceholderText("League TBD") self.le_league.textModified.connect(self.league_changed) policy = QSizePolicy() policy.setHorizontalStretch(3) policy.setHorizontalPolicy(QSizePolicy.Expanding) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) self.le_league.setSizePolicy(policy) self.le_team = [MonitoredLineEdit() for y in range(2)] self.le_player = [[MonitoredLineEdit() for x in range( self.max_no_sets)] for y in range(2)] self.cb_race = [[QComboBox() for x in range(self.max_no_sets)] for y in range(2)] self.sl_score = [QSlider(Qt.Horizontal) for y in range(self.max_no_sets)] self.le_map = [MapLineEdit() for y in range(self.max_no_sets)] self.label_set = [QPushButton('#{}'.format(y + 1), self) for y in range(self.max_no_sets)] self.setContainer = [QHBoxLayout() for y in range(self.max_no_sets)] container = QHBoxLayout() for team_idx in range(2): self.le_team[team_idx].setText("TBD") self.le_team[team_idx].setAlignment( Qt.AlignCenter) self.le_team[team_idx].setPlaceholderText( "Team " + str(team_idx + 1)) policy = QSizePolicy() policy.setHorizontalStretch(4) policy.setHorizontalPolicy( QSizePolicy.Expanding) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) self.le_team[team_idx].setSizePolicy(policy) self.le_team[team_idx].setMinimumWidth(self.mimumLineEditWidth) self.le_team[team_idx].textModified.connect( lambda team_idx=team_idx: self.team_changed(team_idx)) self.qb_logo1 = IconPushButton() self.qb_logo1.setFixedWidth(self.raceWidth) self.qb_logo1.clicked.connect(lambda: self.parent.logoDialog(1, self)) logo = self.controller.logoManager.getTeam1(self._ctrlID) self.qb_logo1.setIcon(QIcon(logo.provideQPixmap())) self.qb_logo2 = IconPushButton() self.qb_logo2.setFixedWidth(self.raceWidth) self.qb_logo2.clicked.connect(lambda: self.parent.logoDialog(2, self)) logo = self.controller.logoManager.getTeam2(self._ctrlID) self.qb_logo2.setIcon(QIcon(logo.provideQPixmap())) self.sl_team = QSlider(Qt.Horizontal) self.sl_team.setTracking(False) self.sl_team.setMinimum(-1) self.sl_team.setMaximum(1) self.sl_team.setValue(0) self.sl_team.setTickPosition( QSlider.TicksBothSides) self.sl_team.setTickInterval(1) self.sl_team.valueChanged.connect(lambda x: self.sl_changed(-1, x)) self.sl_team.setToolTip(_('Choose your team')) self.sl_team.setMinimumHeight(5) self.sl_team.setFixedWidth(self.scoreWidth) policy = QSizePolicy() policy.setHorizontalStretch(0) policy.setHorizontalPolicy(QSizePolicy.Fixed) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) self.sl_team.setSizePolicy(policy) container = QGridLayout() button = QPushButton() pixmap = QIcon( scctool.settings.getResFile('update.png')) button.setIcon(pixmap) button.clicked.connect( lambda: self.controller.swapTeams()) button.setFixedWidth(self.labelWidth) button.setToolTip(_("Swap teams and logos.")) container.addWidget(button, 0, 0, 2, 1) label = QLabel(_("League:")) label.setAlignment(Qt.AlignCenter) policy = QSizePolicy() policy.setHorizontalStretch(4) policy.setHorizontalPolicy(QSizePolicy.Expanding) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) label.setSizePolicy(policy) container.addWidget(label, 0, 1, 1, 1) label = QLabel(_("Maps \ Teams:")) label.setAlignment(Qt.AlignCenter) policy = QSizePolicy() policy.setHorizontalStretch(4) policy.setHorizontalPolicy(QSizePolicy.Expanding) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) label.setSizePolicy(policy) container.addWidget(label, 1, 1, 1, 1) container.addWidget(self.qb_logo1, 0, 2, 2, 1) container.addWidget(self.le_league, 0, 3, 1, 3) container.addWidget(self.le_team[0], 1, 3, 1, 1) container.addWidget(self.sl_team, 1, 4, 1, 1) container.addWidget(self.le_team[1], 1, 5, 1, 1) container.addWidget(self.qb_logo2, 0, 6, 2, 1) layout.addLayout(container) for player_idx in range(self.max_no_sets): self.le_map[player_idx].textModified.connect( lambda player_idx=player_idx: self.map_changed(player_idx)) for team_idx in range(2): self.cb_race[team_idx][player_idx].\ currentIndexChanged.connect( lambda idx, t=team_idx, p=player_idx: self.race_changed(t, p)) self.le_player[team_idx][player_idx].textModified.connect( lambda t=team_idx, p=player_idx: self.player_changed(t, p)) self.le_player[team_idx][player_idx].setText("TBD") self.le_player[team_idx][player_idx].setAlignment( Qt.AlignCenter) self.le_player[team_idx][player_idx].setPlaceholderText( _("Player {} of team {}").format(player_idx + 1, team_idx + 1)) self.le_player[team_idx][player_idx].setMinimumWidth( self.mimumLineEditWidth) self.le_player[team_idx][player_idx].setContextMenuPolicy( Qt.CustomContextMenu) self.le_player[team_idx][player_idx].\ customContextMenuRequested.connect( lambda x, team_idx=team_idx, player_idx=player_idx: self.openPlayerContextMenu(team_idx, player_idx)) for i in range(4): self.cb_race[team_idx][player_idx].addItem( QIcon(scctool.settings.getResFile( str(i) + ".png")), "") self.cb_race[team_idx][player_idx].setFixedWidth( self.raceWidth) self.sl_score[player_idx].setMinimum(-1) self.sl_score[player_idx].setMaximum(1) self.sl_score[player_idx].setValue(0) self.sl_score[player_idx].setTickPosition( QSlider.TicksBothSides) self.sl_score[player_idx].setTickInterval(1) self.sl_score[player_idx].setTracking(False) self.sl_score[player_idx].valueChanged.connect( lambda x, player_idx=player_idx: self.sl_changed(player_idx, x)) self.sl_score[player_idx].setToolTip(_('Set the score')) self.sl_score[player_idx].setFixedWidth(self.scoreWidth) self.le_map[player_idx].setText("TBD") self.le_map[player_idx].setAlignment( Qt.AlignCenter) self.le_map[player_idx].setPlaceholderText( _("Map {}").format(player_idx + 1)) self.le_map[player_idx].setMinimumWidth( self.mimumLineEditWidth) # self.le_map[player_idx].setReadOnly(True) self.setContainer[player_idx] = QHBoxLayout() # self.label_set[player_idx].setText("#" + str(player_idx + 1)) # self.label_set[player_idx].setAlignment( # Qt.AlignCenter) self.label_set[player_idx].setToolTip( _("Select map on Mapstats Browser Source.")) self.label_set[player_idx].setEnabled(False) self.label_set[player_idx].clicked.connect( lambda x, player_idx=player_idx: self.showMap(player_idx)) self.label_set[player_idx].setFixedWidth(self.labelWidth) self.setContainer[player_idx].addWidget( self.label_set[player_idx], 0) self.setContainer[player_idx].addWidget( self.le_map[player_idx], 4) self.setContainer[player_idx].addWidget( self.cb_race[0][player_idx], 0) self.setContainer[player_idx].addWidget( self.le_player[0][player_idx], 4) self.setContainer[player_idx].addWidget( self.sl_score[player_idx], 0) self.setContainer[player_idx].addWidget( self.le_player[1][player_idx], 4) self.setContainer[player_idx].addWidget( self.cb_race[1][player_idx], 0) layout.addLayout(self.setContainer[player_idx]) layout.addItem(QSpacerItem( 0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.setLayout(layout) self.updateMapCompleters() self.updatePlayerCompleters() self.updateTeamCompleters()
class MatchDataWidget(QWidget): """Widget to display matchd data.""" def __init__(self, parent, tabWidget, matchData, closeable=True): """Init widget""" super().__init__(parent) self.max_no_sets = scctool.settings.max_no_sets self.scoreWidth = 35 self.raceWidth = 45 self.labelWidth = 25 self.mimumLineEditWidth = 130 self._tabWidget = tabWidget self.matchData = matchData self._ctrlID = self.matchData.getControlID() self.parent = parent self.controller = parent.controller self.tlock = TriggerLock() self._tabIdx = self._tabWidget.addTab(self, '') with self.tlock: self._createView() self.updateForms() self._radioButton = QRadioButton() self._radioButton.setStyleSheet("color: green") self._radioButton.setToolTip(_('Activate Match')) if self.controller.matchControl.selectedMatchId() == self._ctrlID: self._tabWidget.setCurrentIndex(self._tabIdx) self._tabWidget.tabBar().setTabButton( self._tabIdx, QTabBar.ButtonPosition.LeftSide, self._radioButton) self._radioButton.toggled.connect(self.activate) if self.controller.matchControl.activeMatchId() == self._ctrlID: self.checkButton() self._closeButton = QPushButton() pixmap = QIcon(scctool.settings.getResFile('close.png')) self._closeButton.setIcon(pixmap) self._closeButton.setFlat(True) self._closeButton.clicked.connect(self.closeTab) self._closeButton.setToolTip(_('Close Match')) self._tabWidget.tabBar().setTabButton( self._tabIdx, QTabBar.ButtonPosition.RightSide, self._closeButton) self.setClosable(closeable) def setClosable(self, closeable): self._closeButton.setHidden(not closeable) def closeTab(self): if self._tabWidget.count() > 1: idx = self._tabWidget.indexOf(self) ident = self.matchData.getControlID() self._tabWidget.removeTab(idx) new_index = self.controller.matchControl.removeMatch(ident) if new_index is not None: self._tabWidget.widget(new_index).checkButton() count = self._tabWidget.count() if count == 1: self._tabWidget.widget(0).setClosable(False) def checkButton(self): self._radioButton.setChecked(True) def activate(self, checked): if (checked and self.controller.matchControl.activeMatchId() != self._ctrlID): self.controller.matchControl.activateMatch( self.matchData.getControlID()) self.autoSetNextMap(send=False) self.controller.mapstatsManager.sendMapPool() self.parent.updateAllMapButtons() self.controller.updateLogosWebsocket() elif self.controller.matchControl.countMatches() == 1: self._radioButton.toggled.disconnect() self._radioButton.setChecked(True) self._radioButton.toggled.connect(self.activate) def setName(self): team1 = self.matchData.getTeamOrPlayer(0).replace('&', '&&') team2 = self.matchData.getTeamOrPlayer(1).replace('&', '&&') name = " {} vs {}".format(team1, team2) self._tabWidget.tabBar().setTabText(self._tabIdx, name) def _createView(self): layout = QVBoxLayout() self.le_league = MonitoredLineEdit() self.le_league.setText("League TBD") self.le_league.setAlignment(Qt.AlignCenter) self.le_league.setPlaceholderText("League TBD") self.le_league.textModified.connect(self.league_changed) policy = QSizePolicy() policy.setHorizontalStretch(3) policy.setHorizontalPolicy(QSizePolicy.Expanding) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) self.le_league.setSizePolicy(policy) self.le_team = [MonitoredLineEdit() for y in range(2)] self.le_player = [[MonitoredLineEdit() for x in range( self.max_no_sets)] for y in range(2)] self.cb_race = [[QComboBox() for x in range(self.max_no_sets)] for y in range(2)] self.sl_score = [QSlider(Qt.Horizontal) for y in range(self.max_no_sets)] self.le_map = [MapLineEdit() for y in range(self.max_no_sets)] self.label_set = [QPushButton('#{}'.format(y + 1), self) for y in range(self.max_no_sets)] self.setContainer = [QHBoxLayout() for y in range(self.max_no_sets)] container = QHBoxLayout() for team_idx in range(2): self.le_team[team_idx].setText("TBD") self.le_team[team_idx].setAlignment( Qt.AlignCenter) self.le_team[team_idx].setPlaceholderText( "Team " + str(team_idx + 1)) policy = QSizePolicy() policy.setHorizontalStretch(4) policy.setHorizontalPolicy( QSizePolicy.Expanding) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) self.le_team[team_idx].setSizePolicy(policy) self.le_team[team_idx].setMinimumWidth(self.mimumLineEditWidth) self.le_team[team_idx].textModified.connect( lambda team_idx=team_idx: self.team_changed(team_idx)) self.qb_logo1 = IconPushButton() self.qb_logo1.setFixedWidth(self.raceWidth) self.qb_logo1.clicked.connect(lambda: self.parent.logoDialog(1, self)) logo = self.controller.logoManager.getTeam1(self._ctrlID) self.qb_logo1.setIcon(QIcon(logo.provideQPixmap())) self.qb_logo2 = IconPushButton() self.qb_logo2.setFixedWidth(self.raceWidth) self.qb_logo2.clicked.connect(lambda: self.parent.logoDialog(2, self)) logo = self.controller.logoManager.getTeam2(self._ctrlID) self.qb_logo2.setIcon(QIcon(logo.provideQPixmap())) self.sl_team = QSlider(Qt.Horizontal) self.sl_team.setTracking(False) self.sl_team.setMinimum(-1) self.sl_team.setMaximum(1) self.sl_team.setValue(0) self.sl_team.setTickPosition( QSlider.TicksBothSides) self.sl_team.setTickInterval(1) self.sl_team.valueChanged.connect(lambda x: self.sl_changed(-1, x)) self.sl_team.setToolTip(_('Choose your team')) self.sl_team.setMinimumHeight(5) self.sl_team.setFixedWidth(self.scoreWidth) policy = QSizePolicy() policy.setHorizontalStretch(0) policy.setHorizontalPolicy(QSizePolicy.Fixed) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) self.sl_team.setSizePolicy(policy) container = QGridLayout() button = QPushButton() pixmap = QIcon( scctool.settings.getResFile('update.png')) button.setIcon(pixmap) button.clicked.connect( lambda: self.controller.swapTeams()) button.setFixedWidth(self.labelWidth) button.setToolTip(_("Swap teams and logos.")) container.addWidget(button, 0, 0, 2, 1) label = QLabel(_("League:")) label.setAlignment(Qt.AlignCenter) policy = QSizePolicy() policy.setHorizontalStretch(4) policy.setHorizontalPolicy(QSizePolicy.Expanding) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) label.setSizePolicy(policy) container.addWidget(label, 0, 1, 1, 1) label = QLabel(_("Maps \ Teams:")) label.setAlignment(Qt.AlignCenter) policy = QSizePolicy() policy.setHorizontalStretch(4) policy.setHorizontalPolicy(QSizePolicy.Expanding) policy.setVerticalStretch(1) policy.setVerticalPolicy(QSizePolicy.Fixed) label.setSizePolicy(policy) container.addWidget(label, 1, 1, 1, 1) container.addWidget(self.qb_logo1, 0, 2, 2, 1) container.addWidget(self.le_league, 0, 3, 1, 3) container.addWidget(self.le_team[0], 1, 3, 1, 1) container.addWidget(self.sl_team, 1, 4, 1, 1) container.addWidget(self.le_team[1], 1, 5, 1, 1) container.addWidget(self.qb_logo2, 0, 6, 2, 1) layout.addLayout(container) for player_idx in range(self.max_no_sets): self.le_map[player_idx].textModified.connect( lambda player_idx=player_idx: self.map_changed(player_idx)) for team_idx in range(2): self.cb_race[team_idx][player_idx].\ currentIndexChanged.connect( lambda idx, t=team_idx, p=player_idx: self.race_changed(t, p)) self.le_player[team_idx][player_idx].textModified.connect( lambda t=team_idx, p=player_idx: self.player_changed(t, p)) self.le_player[team_idx][player_idx].setText("TBD") self.le_player[team_idx][player_idx].setAlignment( Qt.AlignCenter) self.le_player[team_idx][player_idx].setPlaceholderText( _("Player {} of team {}").format(player_idx + 1, team_idx + 1)) self.le_player[team_idx][player_idx].setMinimumWidth( self.mimumLineEditWidth) self.le_player[team_idx][player_idx].setContextMenuPolicy( Qt.CustomContextMenu) self.le_player[team_idx][player_idx].\ customContextMenuRequested.connect( lambda x, team_idx=team_idx, player_idx=player_idx: self.openPlayerContextMenu(team_idx, player_idx)) for i in range(4): self.cb_race[team_idx][player_idx].addItem( QIcon(scctool.settings.getResFile( str(i) + ".png")), "") self.cb_race[team_idx][player_idx].setFixedWidth( self.raceWidth) self.sl_score[player_idx].setMinimum(-1) self.sl_score[player_idx].setMaximum(1) self.sl_score[player_idx].setValue(0) self.sl_score[player_idx].setTickPosition( QSlider.TicksBothSides) self.sl_score[player_idx].setTickInterval(1) self.sl_score[player_idx].setTracking(False) self.sl_score[player_idx].valueChanged.connect( lambda x, player_idx=player_idx: self.sl_changed(player_idx, x)) self.sl_score[player_idx].setToolTip(_('Set the score')) self.sl_score[player_idx].setFixedWidth(self.scoreWidth) self.le_map[player_idx].setText("TBD") self.le_map[player_idx].setAlignment( Qt.AlignCenter) self.le_map[player_idx].setPlaceholderText( _("Map {}").format(player_idx + 1)) self.le_map[player_idx].setMinimumWidth( self.mimumLineEditWidth) # self.le_map[player_idx].setReadOnly(True) self.setContainer[player_idx] = QHBoxLayout() # self.label_set[player_idx].setText("#" + str(player_idx + 1)) # self.label_set[player_idx].setAlignment( # Qt.AlignCenter) self.label_set[player_idx].setToolTip( _("Select map on Mapstats Browser Source.")) self.label_set[player_idx].setEnabled(False) self.label_set[player_idx].clicked.connect( lambda x, player_idx=player_idx: self.showMap(player_idx)) self.label_set[player_idx].setFixedWidth(self.labelWidth) self.setContainer[player_idx].addWidget( self.label_set[player_idx], 0) self.setContainer[player_idx].addWidget( self.le_map[player_idx], 4) self.setContainer[player_idx].addWidget( self.cb_race[0][player_idx], 0) self.setContainer[player_idx].addWidget( self.le_player[0][player_idx], 4) self.setContainer[player_idx].addWidget( self.sl_score[player_idx], 0) self.setContainer[player_idx].addWidget( self.le_player[1][player_idx], 4) self.setContainer[player_idx].addWidget( self.cb_race[1][player_idx], 0) layout.addLayout(self.setContainer[player_idx]) layout.addItem(QSpacerItem( 0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.setLayout(layout) self.updateMapCompleters() self.updatePlayerCompleters() self.updateTeamCompleters() def openPlayerContextMenu(self, team_idx, player_idx): menu = self.le_player[team_idx][player_idx].\ createStandardContextMenu() first_action = menu.actions()[0] add_alias_action = QAction('Add Alias') add_alias_action.triggered.connect( lambda x, team_idx=team_idx, player_idx=player_idx: self.addAlias(team_idx, player_idx)) menu.insertAction(first_action, add_alias_action) menu.insertSeparator(first_action) menu.exec_(QCursor.pos()) def addAlias(self, team_idx, player_idx): name = self.le_player[team_idx][player_idx].text().strip() name, ok = QInputDialog.getText( self, _('Player Alias'), _('Name') + ':', text=name) if not ok: return name = name.strip() alias, ok = QInputDialog.getText( self, _('Alias'), _('Alias of {}').format(name) + ':', text="") alias = alias.strip() if not ok: return try: self.controller.aliasManager.addPlayerAlias(name, alias) except Exception as e: module_logger.exception("message") QMessageBox.critical(self, _("Error"), str(e)) def league_changed(self): if not self.tlock.trigger(): return self.matchData.setLeague(self.le_league.text()) def sl_changed(self, set_idx, value): """Handle a new score value.""" try: if self.tlock.trigger(): if set_idx == -1: self.matchData.setMyTeam(value) else: self.matchData.setMapScore(set_idx, value, True) self.allkillUpdate() self.autoSetNextMap() except Exception as e: module_logger.exception("message") def player_changed(self, team_idx, player_idx): """Handle a change of player names.""" if not self.tlock.trigger(): return try: player = self.le_player[team_idx][player_idx].text().strip() race = self.cb_race[team_idx][player_idx].currentIndex() if(player_idx == 0 and self.matchData.getSolo()): for p_idx in range(1, self.max_no_sets): self.le_player[team_idx][p_idx].setText(player) self.player_changed(team_idx, p_idx) self.controller.historyManager.insertPlayer(player, race) self.matchData.setPlayer( team_idx, player_idx, self.le_player[team_idx][player_idx].text()) if race == 0: new_race = scctool.settings.race2idx( self.controller.historyManager.getRace(player)) if new_race != 0: self.cb_race[team_idx][player_idx].setCurrentIndex( new_race) elif player.lower() == "tbd": self.cb_race[team_idx][player_idx].setCurrentIndex(0) self.updatePlayerCompleters() self.setName() except Exception as e: module_logger.exception("message") def race_changed(self, team_idx, player_idx): """Handle a change of player names.""" if not self.tlock.trigger(): return player = self.le_player[team_idx][player_idx].text().strip() race = self.cb_race[team_idx][player_idx].currentIndex() self.controller.historyManager.insertPlayer(player, race) self.matchData.setRace( team_idx, player_idx, scctool.settings.idx2race( self.cb_race[team_idx][player_idx].currentIndex())) try: if(player_idx == 0 and self.matchData.getSolo()): idx = self.cb_race[team_idx][0].currentIndex() for player_idx in range(1, self.max_no_sets): self.cb_race[team_idx][player_idx].setCurrentIndex(idx) except Exception as e: module_logger.exception("message") def team_changed(self, team_idx): if not self.tlock.trigger(): return team = self.le_team[team_idx].text().strip() logo = self.controller.logoManager.getTeam(team_idx + 1).getIdent() if logo == '0': logo = self.controller.historyManager.getLogo(team) if logo != '0': self.controller.logoManager.setTeamLogo(team_idx + 1, logo) self.controller.updateLogos(True) self.controller.historyManager.insertTeam(team, logo) self.updateTeamCompleters() self.matchData.setTeam(team_idx, team) self.matchData.autoSetMyTeam() self.sl_team.setValue(self.matchData.getMyTeam()) self.setName() def map_changed(self, set_idx): if not self.tlock.trigger(): return self.matchData.setMap(set_idx, self.le_map[set_idx].text()) self.updateMapButtons() self.controller.matchControl.activeMatch() self.autoSetNextMap(set_idx) def autoSetNextMap(self, idx=-1, send=True): if self.controller.matchControl.activeMatchId() == self._ctrlID: self.controller.autoSetNextMap(idx, send) def updateMapCompleters(self): """Update the auto completers for maps.""" for i in range(self.max_no_sets): list = scctool.settings.maps.copy() try: list.remove("TBD") except Exception as e: pass finally: list.sort() list.append("TBD") completer = QCompleter(list, self.le_map[i]) completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setFilterMode(Qt.MatchContains) completer.setCompletionMode( QCompleter.UnfilteredPopupCompletion) completer.setWrapAround(True) completer.activated.connect(self.le_map[i].completerFinished) self.le_map[i].setCompleter(completer) def updatePlayerCompleters(self): """Refresh the completer for the player line edits.""" list = scctool.settings.config.getMyPlayers( True) + ["TBD"] + self.controller.historyManager.getPlayerList() for player_idx in range(self.max_no_sets): for team_idx in range(2): completer = QCompleter( list, self.le_player[team_idx][player_idx]) completer.setCaseSensitivity( Qt.CaseInsensitive) completer.setCompletionMode( QCompleter.InlineCompletion) completer.setFilterMode(Qt.MatchContains) completer.setWrapAround(True) completer.activated.connect( self.le_player[team_idx][player_idx].completerFinished) self.le_player[team_idx][player_idx].setCompleter( completer) def updateTeamCompleters(self): """Refresh the completer for the team line edits.""" list = scctool.settings.config.getMyTeams() + \ ["TBD"] + self.controller.historyManager.getTeamList() for team_idx in range(2): completer = QCompleter( list, self.le_team[team_idx]) completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setCompletionMode( QCompleter.InlineCompletion) completer.setFilterMode(Qt.MatchContains) completer.setWrapAround(True) completer.activated.connect( self.le_team[team_idx].completerFinished) self.le_team[team_idx].setCompleter(completer) def updateForms(self): """Update data in forms.""" try: self.le_league.setText( self.matchData.getLeague()) self.sl_team.setValue( self.matchData.getMyTeam()) for i in range(2): team = self.matchData.getTeam(i) self.le_team[i].setText(team) logo = self.controller.logoManager.getTeam(i + 1).getIdent() self.controller.historyManager.insertTeam(team, logo) for j in range(2): for i in range(1, self.matchData.getNoSets()): self.le_player[j][i].setReadOnly( self.matchData.getSolo()) for i in range(min(self.max_no_sets, self.matchData.getNoSets())): for j in range(2): player = self.matchData.getPlayer(j, i) race = self.matchData.getRace(j, i) self.le_player[j][i].setText(player) self.cb_race[j][i].setCurrentIndex( scctool.settings.race2idx(race)) self.controller.historyManager.insertPlayer(player, race) self.le_map[i].setText( self.matchData.getMap(i)) self.sl_score[i].setValue( self.matchData.getMapScore(i)) for i in range(self.matchData.getNoSets(), self.max_no_sets): for j in range(2): self.le_player[j][i].hide() self.cb_race[j][i].hide() self.le_map[i].hide() self.sl_score[i].hide() self.label_set[i].hide() for i in range(min(self.max_no_sets, self.matchData.getNoSets())): for j in range(2): self.le_player[j][i].show() self.cb_race[j][i].show() self.le_map[i].show() self.sl_score[i].show() self.label_set[i].show() self.updatePlayerCompleters() self.updateTeamCompleters() self.updateMapButtons() self.setName() # self.autoSetNextMap() except Exception as e: module_logger.exception("message") raise def updateMapButtons(self): mappool = list(self.controller.mapstatsManager.getMapPool()) for i in range(self.max_no_sets): map = self.matchData.getMap(i) if map in mappool: self.label_set[i].setEnabled(True) else: self.label_set[i].setEnabled(False) if (self.controller.mapstatsManager.getMapPoolType() == 2 and self.controller.matchControl.activeMatchId() == self._ctrlID): self.controller.mapstatsManager.sendMapPool() def updateLogos(self, force=False): """Update team logos in view.""" logo = self.controller.logoManager.getTeam1(self._ctrlID) self.qb_logo1.setIcon(QIcon(logo.provideQPixmap())) logo = self.controller.logoManager.getTeam2(self._ctrlID) self.qb_logo2.setIcon(QIcon(logo.provideQPixmap())) for idx in range(2): team = self.matchData.getTeam(idx) logo = self.controller.logoManager.getTeam( idx + 1, self._ctrlID).getIdent() self.controller.historyManager.insertTeam(team, logo) if self.controller.matchControl.activeMatchId() == self._ctrlID: self.controller.updateLogosWebsocket() def allkillUpdate(self): """In case of allkill move the winner to the next set.""" if(self.matchData.allkillUpdate()): self.updateForms() def setScore(self, idx, score, allkill=True): """Handle change of the score.""" try: if(self.sl_score[idx].value() == 0): self.parent.statusBar().showMessage(_('Updating Score...')) with self.tlock: self.sl_score[idx].setValue(score) self.matchData.setMapScore(idx, score, True) if allkill: self.allkillUpdate() self.autoSetNextMap() if not self.controller.resetWarning(): self.parent.statusBar().showMessage('') return True else: return False except Exception as e: module_logger.exception("message") def showMap(self, player_idx): self.controller.mapstatsManager.selectMap( self.matchData.getMap(player_idx))
def createTabs(self): """Create tabs in main window.""" try: # Initialize tab screen self.tabs = QTabWidget() self.tab1 = QWidget() self.tab2 = QWidget() # self.tabs.resize(300,200) # Add tabs self.tabs.addTab(self.tab1, _("Match Grabber for AlphaTL && RSTL")) self.tabs.addTab(self.tab2, _("Custom Match")) # Create first tab self.tab1.layout = QVBoxLayout() self.le_url = MatchComboBox(self) self.le_url.returnPressed.connect(self.refresh_click) minWidth = self.scoreWidth + 2 * self.raceWidth + \ 2 * self.mimumLineEditWidth + 4 * 6 self.le_url.setMinimumWidth(minWidth) self.pb_openBrowser = QPushButton(_("Open in Browser")) self.pb_openBrowser.clicked.connect(self.openBrowser_click) width = (self.scoreWidth + 2 * self.raceWidth + 2 * self.mimumLineEditWidth + 4 * 6) / 2 - 2 self.pb_openBrowser.setMinimumWidth(width) container = QHBoxLayout() label = QLabel() label.setFixedWidth(self.labelWidth) container.addWidget(label, 0) label = QLabel(_("Match-URL:")) label.setMinimumWidth(80) container.addWidget(label, 0) container.addWidget(self.le_url, 1) button = QPushButton() pixmap = QIcon(scctool.settings.getResFile('alpha.png')) button.setIcon(pixmap) button.clicked.connect( lambda: self.controller.openURL("https://alpha.tl/")) container.addWidget(button, 0) button = QPushButton() pixmap = QIcon(scctool.settings.getResFile('rstl.png')) button.setIcon(pixmap) button.clicked.connect( lambda: self.controller.openURL("http://hdgame.net/en/")) container.addWidget(button, 0) self.tab1.layout = QFormLayout() self.tab1.layout.addRow(container) container = QHBoxLayout() # self.pb_download = QPushButton("Download Images from URL") # container.addWidget(self.pb_download) label = QLabel() label.setFixedWidth(self.labelWidth) container.addWidget(label, 0) label = QLabel() label.setMinimumWidth(80) container.addWidget(label, 0) self.pb_refresh = QPushButton(_("Load Data from URL")) self.pb_refresh.clicked.connect(self.refresh_click) container.addWidget(self.pb_openBrowser, 3) container.addWidget(self.pb_refresh, 3) self.tab1.layout.addRow(container) self.tab1.setLayout(self.tab1.layout) # Create second tab self.tab2.layout = QVBoxLayout() container = QHBoxLayout() label = QLabel() label.setMinimumWidth(self.labelWidth) container.addWidget(label, 0) label = QLabel(_("Match Format:")) label.setMinimumWidth(80) container.addWidget(label, 0) container.addWidget(QLabel(_("Best of")), 0) self.cb_bestof = QComboBox() for idx in range(0, scctool.settings.max_no_sets): self.cb_bestof.addItem(str(idx + 1)) self.cb_bestof.setCurrentIndex(3) string = _('"Best of 6/4": First, a Bo5/3 is played and the' ' ace map gets extended to a Bo3 if needed;' ' Best of 2: Bo3 with only two maps played.') self.cb_bestof.setToolTip(string) self.cb_bestof.setMaximumWidth(40) self.cb_bestof.currentIndexChanged.connect(self.changeBestOf) container.addWidget(self.cb_bestof, 0) container.addWidget(QLabel(_(" but at least")), 0) self.cb_minSets = QComboBox() self.cb_minSets.setToolTip( _('Minimum number of maps played (even if the match' ' is decided already)')) self.cb_minSets.setMaximumWidth(40) container.addWidget(self.cb_minSets, 0) container.addWidget(QLabel(" " + _("maps") + " "), 0) self.cb_minSets.currentIndexChanged.connect( lambda idx: self.highlightApplyCustom()) self.cb_allkill = QCheckBox(_("All-Kill Format")) self.cb_allkill.setChecked(False) self.cb_allkill.setToolTip( _('Winner stays and is automatically' ' placed into the next set')) self.cb_allkill.stateChanged.connect(self.allkill_change) container.addWidget(self.cb_allkill, 0) self.cb_solo = QCheckBox(_("1vs1")) self.cb_solo.setChecked(False) self.cb_solo.setToolTip(_('Select for solo (non-team matches)')) container.addWidget(self.cb_solo, 0) self.cb_solo.stateChanged.connect( lambda idx: self.highlightApplyCustom()) label = QLabel("") container.addWidget(label, 1) self.applycustom_is_highlighted = False self.pb_applycustom = QToolButton() action = QAction(_("Apply Format")) action.triggered.connect(self.applycustom_click) self.pb_applycustom.setDefaultAction(action) self.custom_menu = QMenu(self.pb_applycustom) for format, icon in \ self.controller.matchControl.getCustomFormats(): if icon: action = self.custom_menu.addAction( QIcon(scctool.settings.getResFile(icon)), format) else: action = self.custom_menu.addAction(format) action.triggered.connect( lambda x, format=format: self.applyCustomFormat(format)) self.pb_applycustom.setMenu(self.custom_menu) self.pb_applycustom.setPopupMode(QToolButton.MenuButtonPopup) self.pb_applycustom.setFixedWidth(150) container.addWidget(self.pb_applycustom, 0) self.defaultButtonPalette = self.pb_applycustom.palette() self.tab2.layout.addLayout(container) container = QHBoxLayout() label = QLabel() label.setMinimumWidth(self.labelWidth) container.addWidget(label, 0) label = QLabel(_("Match-URL:")) label.setMinimumWidth(80) container.addWidget(label, 0) self.le_url_custom = MonitoredLineEdit() self.le_url_custom.setAlignment(Qt.AlignCenter) self.le_url_custom.setToolTip( _('Optionally specify the Match-URL,' ' e.g., for Nightbot commands')) self.le_url_custom.setPlaceholderText( _("Specify the Match-URL of your Custom Match")) completer = QCompleter(["http://"], self.le_url_custom) completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) completer.setWrapAround(True) self.le_url_custom.setCompleter(completer) self.le_url_custom.setMinimumWidth(360) self.le_url_custom.textModified.connect(self.highlightApplyCustom) container.addWidget(self.le_url_custom, 11) label = QLabel("") container.addWidget(label, 1) self.pb_resetdata = QPushButton(_("Reset Match Data")) self.pb_resetdata.setFixedWidth(150) self.pb_resetdata.clicked.connect(self.resetdata_click) container.addWidget(self.pb_resetdata, 0) self.tab2.layout.addLayout(container) self.tab2.setLayout(self.tab2.layout) except Exception as e: module_logger.exception("message")
class MainWindow(QMainWindow): """Show the main window of SCCT.""" EXIT_CODE_REBOOT = -123 def __init__(self, controller, app, showChangelog): """Init the main window.""" try: super().__init__() self._save = True self.tlock = TriggerLock() self.controller = controller self.max_no_sets = scctool.settings.max_no_sets self.scoreWidth = 35 self.raceWidth = 45 self.labelWidth = 25 self.mimumLineEditWidth = 130 self.createTabs() self.createMatchDataTabs() self.createHorizontalGroupBox() self.createLowerTabWidget() self.createMenuBar() mainLayout = QVBoxLayout() mainLayout.addWidget(self.tabs, 0) mainLayout.addWidget(self.matchDataTabWidget, 1) # mainLayout.addWidget(self.fromMatchDataBox, 1) mainLayout.addWidget(self.lowerTabWidget, 0) mainLayout.addWidget(self.horizontalGroupBox, 0) self.setWindowTitle("StarCraft Casting Tool v{}".format( scctool.__version__)) self.window = QWidget() self.window.setLayout(mainLayout) self.setCentralWidget(self.window) # self.size self.statusBar() self.leds = dict() for scope in self.controller.websocketThread.get_primary_scopes(): self.leds[scope] = LedIndicator(self) for key, led in self.leds.items(): self.controller.toogleLEDs(0, key, self) self.statusBar().addPermanentWidget(led) self.app = app self.controller.setView(self) self.controller.refreshButtonStatus() self.processEvents() self.settings = QSettings(ClientConfig.APP_NAME, ClientConfig.COMPANY_NAME) self.restoreGeometry( self.settings.value("geometry", self.saveGeometry())) self.restoreState( self.settings.value("windowState", self.saveState())) self.mysubwindows = dict() self.show() self.raise_() if showChangelog: self.openChangelog() except Exception as e: module_logger.exception("message") def showAbout(self): """Show subwindow with about info.""" html = markdown2.markdown_path(scctool.settings.getResFile("about.md")) html = html.replace("%VERSION%", scctool.__version__) if (not scctool.__new_version__): new_version = _("StarCraft Casting Tool is up to date.") else: new_version = _("The new version {} is available!").format( scctool.__latest_version__) html = html.replace('%NEW_VERSION%', new_version) # use self as parent here QMessageBox.about(self, _("StarCraft Casting Tool - About"), html) def closeEvent(self, event): """Close and clean up window.""" try: try: for name, window in self.mysubwindows.items(): if (window and window.isVisible()): window.close() finally: self.settings.setValue("geometry", self.saveGeometry()) self.settings.setValue("windowState", self.saveState()) self.controller.cleanUp(self._save) QMainWindow.closeEvent(self, event) # event.accept() except Exception as e: module_logger.exception("message") def createMenuBar(self): """Create the menu bar.""" try: menubar = self.menuBar() settingsMenu = menubar.addMenu(_('Settings')) apiAct = QAction(QIcon(scctool.settings.getResFile('browser.png')), _('Browser Sources'), self) apiAct.setToolTip(_('Edit Settings for all Browser Sources')) apiAct.triggered.connect(self.openBrowserSourcesDialog) settingsMenu.addAction(apiAct) apiAct = QAction(QIcon(scctool.settings.getResFile('twitch.png')), _('Twitch && Nightbot'), self) apiAct.setToolTip( _('Edit Intro-Settings and API-Settings' ' for Twitch and Nightbot')) apiAct.triggered.connect(self.openApiDialog) settingsMenu.addAction(apiAct) styleAct = QAction( QIcon(scctool.settings.getResFile('pantone.png')), _('Styles'), self) styleAct.setToolTip('') styleAct.triggered.connect(self.openStyleDialog) settingsMenu.addAction(styleAct) miscAct = QAction( QIcon(scctool.settings.getResFile('settings.png')), _('Misc'), self) miscAct.setToolTip('') miscAct.triggered.connect(self.openMiscDialog) settingsMenu.addAction(miscAct) self.createBrowserSrcMenu() ProfileMenu(self, self.controller) self.createLangMenu() infoMenu = menubar.addMenu(_('Info && Links')) myAct = QAction(QIcon(scctool.settings.getResFile('about.png')), _('About'), self) myAct.triggered.connect(self.showAbout) infoMenu.addAction(myAct) myAct = QAction(QIcon(scctool.settings.getResFile('readme.ico')), _('Readme'), self) myAct.triggered.connect(self.openReadme) infoMenu.addAction(myAct) websiteAct = QAction( QIcon(scctool.settings.getResFile('youtube.png')), _('Video Tutorial'), self) websiteAct.triggered.connect(lambda: self.controller.openURL( "https://youtu.be/j5iWa4JB8bM")) infoMenu.addAction(websiteAct) myAct = QAction(QIcon(scctool.settings.getResFile('update.png')), _('Check for new version'), self) myAct.triggered.connect(lambda: self.controller.checkVersion(True)) infoMenu.addAction(myAct) myAct = QAction( QIcon(scctool.settings.getResFile('changelog.png')), _('Changelog'), self) myAct.triggered.connect(self.openChangelog) infoMenu.addAction(myAct) myAct = QAction(QIcon(scctool.settings.getResFile('folder.png')), _('Open log folder'), self) myAct.triggered.connect(lambda: self.controller.open_file( scctool.settings.getAbsPath(scctool.settings.getLogDir()))) infoMenu.addAction(myAct) infoMenu.addSeparator() websiteAct = QAction( QIcon(scctool.settings.getResFile('scct.ico')), 'StarCraft Casting Tool', self) websiteAct.triggered.connect(lambda: self.controller.openURL( "https://teampheenix.github.io/StarCraft-Casting-Tool/")) infoMenu.addAction(websiteAct) discordAct = QAction( QIcon(scctool.settings.getResFile('discord.png')), 'Discord', self) discordAct.triggered.connect( lambda: self.controller.openURL("https://discord.gg/G9hFEfh")) infoMenu.addAction(discordAct) ixAct = QAction(QIcon(scctool.settings.getResFile('icon.png')), 'team pheeniX', self) ixAct.triggered.connect( lambda: self.controller.openURL("http://team-pheenix.de")) infoMenu.addAction(ixAct) alphaAct = QAction(QIcon(scctool.settings.getResFile('alpha.png')), 'AlphaTL', self) alphaAct.triggered.connect( lambda: self.controller.openURL("https://alpha.tl")) infoMenu.addAction(alphaAct) rstlAct = QAction(QIcon(scctool.settings.getResFile('rstl.png')), 'RSTL', self) rstlAct.triggered.connect( lambda: self.controller.openURL("http://hdgame.net/en/")) infoMenu.addAction(rstlAct) infoMenu.addSeparator() myAct = QAction(QIcon(scctool.settings.getResFile('patreon.png')), _('Become a Patron'), self) myAct.triggered.connect(lambda: self.controller.openURL( "https://www.patreon.com/StarCraftCastingTool")) infoMenu.addAction(myAct) myAct = QAction(QIcon(scctool.settings.getResFile('donate.ico')), _('Donate via PayPal'), self) myAct.triggered.connect(lambda: self.controller.openURL( "https://paypal.me/StarCraftCastingTool")) infoMenu.addAction(myAct) except Exception as e: module_logger.exception("message") def createLangMenu(self): menubar = self.menuBar() langMenu = menubar.addMenu(_('Language')) language = scctool.settings.config.parser.get("SCT", "language") languages = [] languages.append({ 'handle': 'de_DE', 'icon': 'de.png', 'name': 'Deutsch', 'active': True }) languages.append({ 'handle': 'en_US', 'icon': 'en.png', 'name': 'English', 'active': True }) languages.append({ 'handle': 'fr_FR', 'icon': 'fr.png', 'name': 'Français', 'active': True }) languages.append({ 'handle': 'ru_RU', 'icon': 'ru.png', 'name': 'Pусский', 'active': True }) for lang in languages: myAct = QAction(QIcon(scctool.settings.getResFile(lang['icon'])), lang['name'], self, checkable=True) myAct.setChecked(language == lang['handle']) myAct.setDisabled(not lang['active']) myAct.triggered.connect( lambda x, handle=lang['handle']: self.changeLanguage(handle)) langMenu.addAction(myAct) def createBrowserSrcMenu(self): menubar = self.menuBar() main_menu = menubar.addMenu(_('Browser Sources')) srcs = [] srcs.append({ 'name': _('Intro'), 'file': 'intro.html', 'settings': lambda: self.openBrowserSourcesDialog('intro') }) srcs.append({ 'name': _('Mapstats'), 'file': 'mapstats.html', 'settings': lambda: self.openBrowserSourcesDialog('mapstats') }) srcs.append({'name': _('Score'), 'file': 'score.html'}) srcs.append({ 'name': _('Map Icons Box'), 'settings': lambda: self.openBrowserSourcesDialog('mapicons_box'), 'sub': [{ 'name': _('Icon Set {}').format(1), 'file': 'mapicons_box_1.html' }, { 'name': _('Icon Set {}').format(2), 'file': 'mapicons_box_2.html' }, { 'name': _('Icon Set {}').format(3), 'file': 'mapicons_box_3.html' }] }) srcs.append({ 'name': _('Map Icons Landscape'), 'settings': lambda: self.openBrowserSourcesDialog("mapicons_landscape"), 'sub': [{ 'name': _('Icon Set {}').format(1), 'file': 'mapicons_landscape_1.html' }, { 'name': _('Icon Set {}').format(2), 'file': 'mapicons_landscape_2.html' }, { 'name': _('Icon Set {}').format(3), 'file': 'mapicons_landscape_3.html' }] }) srcs.append({ 'name': _('Misc'), 'sub': [{ 'name': _('Logo {}').format(1), 'file': 'logo1.html' }, { 'name': _('Logo {}').format(2), 'file': 'logo2.html' }, { 'name': _('UI Logo {}').format(1), 'file': 'ui_logo_1.html' }, { 'name': _('UI Logo {}').format(2), 'file': 'ui_logo_2.html' }, { 'name': _('Aligulac (only 1vs1)'), 'file': 'aligulac.html' }, { 'name': _('Countdown'), 'file': 'countdown.html' }, { 'name': _('League (ALphaTL && RSTL only)'), 'file': 'league.html' }, { 'name': _('Matchbanner (AlphaTL)'), 'file': 'matchbanner.html', 'settings': lambda: self.openMiscDialog('alphatl') }] }) act = QAction(QIcon(scctool.settings.getResFile('folder.png')), _('Open Folder'), self) act.triggered.connect(lambda: self.controller.open_file( scctool.settings.getAbsPath(scctool.settings.casting_html_dir))) main_menu.addAction(act) main_menu.addSeparator() for src in srcs: myMenu = QMenu(src['name'], self) sub = src.get('sub', False) if sub: for icon in sub: mySubMenu = QMenu(icon['name'], self) icon['file'] = os.path.join( scctool.settings.casting_html_dir, icon['file']) act = QAction( QIcon(scctool.settings.getResFile('html.png')), _('Open in Browser'), self) act.triggered.connect( lambda x, file=icon['file']: self.controller.openURL( scctool.settings.getAbsPath(file))) mySubMenu.addAction(act) act = QAction( QIcon(scctool.settings.getResFile('copy.png')), _('Copy URL to Clipboard'), self) act.triggered.connect( lambda x, file=icon['file']: QApplication.clipboard( ).setText(scctool.settings.getAbsPath(file))) mySubMenu.addAction(act) if icon.get('settings', None) is not None: act = QAction( QIcon(scctool.settings.getResFile('browser.png')), _('Settings'), self) act.triggered.connect(icon['settings']) mySubMenu.addAction(act) myMenu.addMenu(mySubMenu) else: src['file'] = os.path.join(scctool.settings.casting_html_dir, src['file']) act = QAction(QIcon(scctool.settings.getResFile('html.png')), _('Open in Browser'), self) act.triggered.connect( lambda x, file=src['file']: self.controller.openURL( scctool.settings.getAbsPath(file))) myMenu.addAction(act) act = QAction(QIcon(scctool.settings.getResFile('copy.png')), _('Copy URL to Clipboard'), self) act.triggered.connect( lambda x, file=src['file']: QApplication.clipboard( ).setText(scctool.settings.getAbsPath(file))) myMenu.addAction(act) if src.get('settings', None) is not None: act = QAction( QIcon(scctool.settings.getResFile('browser.png')), _('Settings'), self) act.triggered.connect(src['settings']) myMenu.addAction(act) main_menu.addMenu(myMenu) main_menu.addSeparator() apiAct = QAction(QIcon(scctool.settings.getResFile('browser.png')), _('Settings'), self) apiAct.setToolTip(_('Edit Settings for all Browser Sources')) apiAct.triggered.connect(self.openBrowserSourcesDialog) main_menu.addAction(apiAct) styleAct = QAction(QIcon(scctool.settings.getResFile('pantone.png')), _('Styles'), self) styleAct.setToolTip('') styleAct.triggered.connect(self.openStyleDialog) main_menu.addAction(styleAct) def openApiDialog(self): """Open subwindow with connection settings.""" self.mysubwindows['connections'] = SubwindowConnections() self.mysubwindows['connections'].createWindow(self) self.mysubwindows['connections'].show() def openStyleDialog(self): """Open subwindow with style settings.""" self.mysubwindows['styles'] = SubwindowStyles() self.mysubwindows['styles'].createWindow(self) self.mysubwindows['styles'].show() def openMiscDialog(self, tab=''): """Open subwindow with misc settings.""" self.mysubwindows['misc'] = SubwindowMisc() self.mysubwindows['misc'].createWindow(self, tab) self.mysubwindows['misc'].show() def openBrowserSourcesDialog(self, tab=''): """Open subwindow with misc settings.""" self.mysubwindows['browser'] = SubwindowBrowserSources() self.mysubwindows['browser'].createWindow(self, tab) self.mysubwindows['browser'].show() def openReadme(self): """Open subwindow with readme viewer.""" self.mysubwindows['readme'] = SubwindowMarkdown() self.mysubwindows['readme'].createWindow( self, _("Readme"), scctool.settings.getResFile('readme.ico'), scctool.settings.getResFile("../README.md")) self.mysubwindows['readme'].show() def openChangelog(self): """Open subwindow with readme viewer.""" self.mysubwindows['changelog'] = SubwindowMarkdown() self.mysubwindows['changelog'].createWindow( self, "StarCraft Casting Tool " + _("Changelog"), scctool.settings.getResFile("changelog.png"), scctool.settings.getResFile("../CHANGELOG.md")) self.mysubwindows['changelog'].show() def changeLanguage(self, language): """Change the language.""" scctool.settings.config.parser.set("SCT", "language", language) self.restart() def updateAllMapCompleters(self): for idx in range(self.matchDataTabWidget.count()): self.matchDataTabWidget.widget(idx).updateMapCompleters() def updateAllPlayerCompleters(self): for idx in range(self.matchDataTabWidget.count()): self.matchDataTabWidget.widget(idx).updatePlayerCompleters() def updateAllMapButtons(self): for idx in range(self.matchDataTabWidget.count()): self.matchDataTabWidget.widget(idx).updateMapButtons() def createMatchDataTabs(self): self.matchDataTabWidget = QTabWidget() self.matchDataTabWidget.setMovable(True) closeable = self.controller.matchControl.countMatches() > 1 self.matchDataTabWidget.setUsesScrollButtons(True) for match in self.controller.matchControl.getMatches(): MatchDataWidget(self, self.matchDataTabWidget, match, closeable) container = QWidget() buttonLayout = QHBoxLayout() buttonLayout.setContentsMargins(2, 1, 1, 2) buttonLayout.setSpacing(1) button = QPushButton() pixmap = QIcon(scctool.settings.getResFile('add.png')) button.setIcon(pixmap) button.setFixedSize(28, 28) # button.setFlat(True) button.setToolTip(_('Add Match Tab')) button.clicked.connect(self.addMatchTab) buttonLayout.addWidget(button) button = QPushButton() button.setFixedSize(28, 28) pixmap = QIcon(scctool.settings.getResFile('copy.png')) button.setIcon(pixmap) # button.setFlat(True) button.setToolTip(_('Copy Match Tab')) button.clicked.connect(self.copyMatchTab) buttonLayout.addWidget(button) container.setLayout(buttonLayout) self.matchDataTabWidget.setCornerWidget(container) tabBar = self.matchDataTabWidget.tabBar() tabBar.setExpanding(True) self.matchDataTabWidget.currentChanged.connect( self.currentMatchTabChanged) tabBar.tabMoved.connect(self.tabMoved) def addMatchTab(self): match = self.controller.matchControl.newMatchData() MatchDataWidget(self, self.matchDataTabWidget, match) count = self.matchDataTabWidget.count() self.matchDataTabWidget.setCurrentIndex(count - 1) if count > 1: for idx in range(count): self.matchDataTabWidget.widget(idx).setClosable(True) def copyMatchTab(self): matchId = self.controller.matchControl.selectedMatchId() data = self.controller.matchControl.selectedMatch().getData() match = self.controller.matchControl.newMatchData(data) self.controller.logoManager.copyMatch(match.getControlID(), matchId) MatchDataWidget(self, self.matchDataTabWidget, match) count = self.matchDataTabWidget.count() self.matchDataTabWidget.setCurrentIndex(count - 1) if count > 1: for idx in range(count): self.matchDataTabWidget.widget(idx).setClosable(True) def currentMatchTabChanged(self, idx): dataWidget = self.matchDataTabWidget.widget(idx) ident = dataWidget.matchData.getControlID() self.controller.matchControl.selectMatch(ident) with self.tlock: self.controller.updateMatchFormat() def tabMoved(self, toIdx, fromIdx): self.controller.matchControl.updateOrder(toIdx, fromIdx) def createTabs(self): """Create tabs in main window.""" try: # Initialize tab screen self.tabs = QTabWidget() self.tab1 = QWidget() self.tab2 = QWidget() # self.tabs.resize(300,200) # Add tabs self.tabs.addTab(self.tab1, _("Match Grabber for AlphaTL && RSTL")) self.tabs.addTab(self.tab2, _("Custom Match")) # Create first tab self.tab1.layout = QVBoxLayout() self.le_url = MatchComboBox(self) self.le_url.returnPressed.connect(self.refresh_click) minWidth = self.scoreWidth + 2 * self.raceWidth + \ 2 * self.mimumLineEditWidth + 4 * 6 self.le_url.setMinimumWidth(minWidth) self.pb_openBrowser = QPushButton(_("Open in Browser")) self.pb_openBrowser.clicked.connect(self.openBrowser_click) width = (self.scoreWidth + 2 * self.raceWidth + 2 * self.mimumLineEditWidth + 4 * 6) / 2 - 2 self.pb_openBrowser.setMinimumWidth(width) container = QHBoxLayout() label = QLabel() label.setFixedWidth(self.labelWidth) container.addWidget(label, 0) label = QLabel(_("Match-URL:")) label.setMinimumWidth(80) container.addWidget(label, 0) container.addWidget(self.le_url, 1) button = QPushButton() pixmap = QIcon(scctool.settings.getResFile('alpha.png')) button.setIcon(pixmap) button.clicked.connect( lambda: self.controller.openURL("https://alpha.tl/")) container.addWidget(button, 0) button = QPushButton() pixmap = QIcon(scctool.settings.getResFile('rstl.png')) button.setIcon(pixmap) button.clicked.connect( lambda: self.controller.openURL("http://hdgame.net/en/")) container.addWidget(button, 0) self.tab1.layout = QFormLayout() self.tab1.layout.addRow(container) container = QHBoxLayout() # self.pb_download = QPushButton("Download Images from URL") # container.addWidget(self.pb_download) label = QLabel() label.setFixedWidth(self.labelWidth) container.addWidget(label, 0) label = QLabel() label.setMinimumWidth(80) container.addWidget(label, 0) self.pb_refresh = QPushButton(_("Load Data from URL")) self.pb_refresh.clicked.connect(self.refresh_click) container.addWidget(self.pb_openBrowser, 3) container.addWidget(self.pb_refresh, 3) self.tab1.layout.addRow(container) self.tab1.setLayout(self.tab1.layout) # Create second tab self.tab2.layout = QVBoxLayout() container = QHBoxLayout() label = QLabel() label.setMinimumWidth(self.labelWidth) container.addWidget(label, 0) label = QLabel(_("Match Format:")) label.setMinimumWidth(80) container.addWidget(label, 0) container.addWidget(QLabel(_("Best of")), 0) self.cb_bestof = QComboBox() for idx in range(0, scctool.settings.max_no_sets): self.cb_bestof.addItem(str(idx + 1)) self.cb_bestof.setCurrentIndex(3) string = _('"Best of 6/4": First, a Bo5/3 is played and the' ' ace map gets extended to a Bo3 if needed;' ' Best of 2: Bo3 with only two maps played.') self.cb_bestof.setToolTip(string) self.cb_bestof.setMaximumWidth(40) self.cb_bestof.currentIndexChanged.connect(self.changeBestOf) container.addWidget(self.cb_bestof, 0) container.addWidget(QLabel(_(" but at least")), 0) self.cb_minSets = QComboBox() self.cb_minSets.setToolTip( _('Minimum number of maps played (even if the match' ' is decided already)')) self.cb_minSets.setMaximumWidth(40) container.addWidget(self.cb_minSets, 0) container.addWidget(QLabel(" " + _("maps") + " "), 0) self.cb_minSets.currentIndexChanged.connect( lambda idx: self.highlightApplyCustom()) self.cb_allkill = QCheckBox(_("All-Kill Format")) self.cb_allkill.setChecked(False) self.cb_allkill.setToolTip( _('Winner stays and is automatically' ' placed into the next set')) self.cb_allkill.stateChanged.connect(self.allkill_change) container.addWidget(self.cb_allkill, 0) self.cb_solo = QCheckBox(_("1vs1")) self.cb_solo.setChecked(False) self.cb_solo.setToolTip(_('Select for solo (non-team matches)')) container.addWidget(self.cb_solo, 0) self.cb_solo.stateChanged.connect( lambda idx: self.highlightApplyCustom()) label = QLabel("") container.addWidget(label, 1) self.applycustom_is_highlighted = False self.pb_applycustom = QToolButton() action = QAction(_("Apply Format")) action.triggered.connect(self.applycustom_click) self.pb_applycustom.setDefaultAction(action) self.custom_menu = QMenu(self.pb_applycustom) for format, icon in \ self.controller.matchControl.getCustomFormats(): if icon: action = self.custom_menu.addAction( QIcon(scctool.settings.getResFile(icon)), format) else: action = self.custom_menu.addAction(format) action.triggered.connect( lambda x, format=format: self.applyCustomFormat(format)) self.pb_applycustom.setMenu(self.custom_menu) self.pb_applycustom.setPopupMode(QToolButton.MenuButtonPopup) self.pb_applycustom.setFixedWidth(150) container.addWidget(self.pb_applycustom, 0) self.defaultButtonPalette = self.pb_applycustom.palette() self.tab2.layout.addLayout(container) container = QHBoxLayout() label = QLabel() label.setMinimumWidth(self.labelWidth) container.addWidget(label, 0) label = QLabel(_("Match-URL:")) label.setMinimumWidth(80) container.addWidget(label, 0) self.le_url_custom = MonitoredLineEdit() self.le_url_custom.setAlignment(Qt.AlignCenter) self.le_url_custom.setToolTip( _('Optionally specify the Match-URL,' ' e.g., for Nightbot commands')) self.le_url_custom.setPlaceholderText( _("Specify the Match-URL of your Custom Match")) completer = QCompleter(["http://"], self.le_url_custom) completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) completer.setWrapAround(True) self.le_url_custom.setCompleter(completer) self.le_url_custom.setMinimumWidth(360) self.le_url_custom.textModified.connect(self.highlightApplyCustom) container.addWidget(self.le_url_custom, 11) label = QLabel("") container.addWidget(label, 1) self.pb_resetdata = QPushButton(_("Reset Match Data")) self.pb_resetdata.setFixedWidth(150) self.pb_resetdata.clicked.connect(self.resetdata_click) container.addWidget(self.pb_resetdata, 0) self.tab2.layout.addLayout(container) self.tab2.setLayout(self.tab2.layout) except Exception as e: module_logger.exception("message") def allkill_change(self): try: self.controller.matchControl.\ selectedMatch().setAllKill(self.cb_allkill.isChecked()) except Exception as e: module_logger.exception("message") def changeBestOf(self, bestof): """Change the minimum sets combo box on change of BoX.""" bestof = bestof + 1 self.cb_minSets.clear() self.highlightApplyCustom() for idx in range(0, bestof): self.cb_minSets.addItem(str(idx + 1)) if bestof == 2: self.cb_minSets.setCurrentIndex(1) else: self.cb_minSets.setCurrentIndex((bestof - 1) / 2) def createHorizontalGroupBox(self): """Create horizontal group box for tasks.""" try: self.horizontalGroupBox = QGroupBox(_("Tasks")) layout = QHBoxLayout() self.pb_twitchupdate = QPushButton(_("Update Twitch Title")) self.pb_twitchupdate.clicked.connect(self.updatetwitch_click) self.pb_nightbotupdate = QPushButton(_("Update Nightbot")) self.pb_nightbotupdate.clicked.connect(self.updatenightbot_click) self.pb_resetscore = QPushButton(_("Reset Score")) self.pb_resetscore.clicked.connect(self.resetscore_click) layout.addWidget(self.pb_twitchupdate) layout.addWidget(self.pb_nightbotupdate) layout.addWidget(self.pb_resetscore) self.horizontalGroupBox.setLayout(layout) except Exception as e: module_logger.exception("message") def createLowerTabWidget(self): """Create the tab widget at the bottom.""" try: self.lowerTabWidget = QTabWidget() self.createBackgroundTasksTab() self.countdownTab = CountdownWidget(self.controller, self) self.lowerTabWidget.addTab(self.backgroundTasksTab, _("Background Tasks")) self.lowerTabWidget.addTab(self.countdownTab, _("Countdown")) except Exception as e: module_logger.exception("message") def createBackgroundTasksTab(self): """Create group box for background tasks.""" try: self.backgroundTasksTab = QWidget() self.cb_autoUpdate = QCheckBox(_("Auto Score Update")) self.cb_autoUpdate.setChecked(False) string = _('Automatically detects the outcome' + ' of SC2 matches that are ' + 'played/observed in your SC2-client' + ' and updates the score accordingly.') self.cb_autoUpdate.setToolTip(string) self.cb_autoUpdate.stateChanged.connect(self.autoUpdate_change) self.cb_autoToggleScore = QCheckBox(_("Set Ingame Score")) self.cb_autoToggleScore.setChecked(False) string = _('Automatically sets the score of your ingame' + ' UI-interface at the begining of a game.') self.cb_autoToggleScore.setToolTip(string) self.cb_autoToggleScore.stateChanged.connect( self.autoToggleScore_change) self.cb_autoToggleProduction = QCheckBox( _("Toggle Production Tab")) self.cb_autoToggleProduction.setChecked(False) string = _('Automatically toggles the production tab of your' + ' ingame UI-interface at the begining of a game.') self.cb_autoToggleProduction.setToolTip(string) self.cb_autoToggleProduction.stateChanged.connect( self.autoToggleProduction_change) self.cb_autoTwitch = QCheckBox(_("Auto Twitch Update")) self.cb_autoTwitch.setChecked(False) self.cb_autoTwitch.stateChanged.connect(self.autoTwitch_change) self.cb_autoNightbot = QCheckBox(_("Auto Nightbot Update")) self.cb_autoNightbot.setChecked(False) self.cb_autoNightbot.stateChanged.connect(self.autoNightbot_change) if (not scctool.settings.windows): self.cb_autoToggleScore.setEnabled(False) self.cb_autoToggleScore.setAttribute(Qt.WA_AlwaysShowToolTips) self.cb_autoToggleScore.setToolTip(_('Only Windows')) self.cb_autoToggleProduction.setEnabled(False) self.cb_autoToggleProduction.setAttribute( Qt.WA_AlwaysShowToolTips) self.cb_autoToggleProduction.setToolTip(_('Only Windows')) layout = QGridLayout() layout.addWidget(self.cb_autoTwitch, 0, 0) layout.addWidget(self.cb_autoNightbot, 0, 1) layout.addWidget(self.cb_autoUpdate, 1, 0) layout.addWidget(self.cb_autoToggleScore, 1, 1) layout.addWidget(self.cb_autoToggleProduction, 1, 2) self.backgroundTasksTab.setLayout(layout) except Exception as e: module_logger.exception("message") def autoTwitch_change(self): """Handle change of auto twitch check box.""" try: if (self.cb_autoTwitch.isChecked()): self.controller.autoRequestsThread.activateTask('twitch') else: self.controller.autoRequestsThread.deactivateTask('twitch') except Exception as e: module_logger.exception("message") def autoNightbot_change(self): """Handle change of auto twitch check box.""" try: if (self.cb_autoNightbot.isChecked()): self.controller.autoRequestsThread.activateTask('nightbot') else: self.controller.autoRequestsThread.deactivateTask('nightbot') except Exception as e: module_logger.exception("message") def autoUpdate_change(self): """Handle change of auto score update check box.""" try: if (self.cb_autoUpdate.isChecked()): self.controller.runSC2ApiThread("updateScore") else: self.controller.stopSC2ApiThread("updateScore") except Exception as e: module_logger.exception("message") def autoToggleScore_change(self): """Handle change of toggle score check box.""" try: if (self.cb_autoToggleScore.isChecked()): self.controller.runSC2ApiThread("toggleScore") else: self.controller.stopSC2ApiThread("toggleScore") except Exception as e: module_logger.exception("message") def autoToggleProduction_change(self): """Handle change of toggle production tab check box.""" try: if (self.cb_autoToggleProduction.isChecked()): self.controller.runSC2ApiThread("toggleProduction") else: self.controller.stopSC2ApiThread("toggleProduction") except Exception as e: module_logger.exception("message") def applyCustomFormat(self, format): """Handle click to apply custom format.""" QApplication.setOverrideCursor(Qt.WaitCursor) try: with self.tlock: self.controller.matchControl.\ selectedMatch().applyCustomFormat(format) self.controller.updateMatchFormat() matchWidget = self.matchDataTabWidget.currentWidget() matchWidget.updateForms() self.resizeWindow() self.highlightApplyCustom(False) except Exception as e: module_logger.exception("message") finally: QApplication.restoreOverrideCursor() def applycustom_click(self): """Handle click to apply custom match.""" QApplication.setOverrideCursor(Qt.WaitCursor) try: with self.tlock: self.statusBar().showMessage(_('Applying Custom Match...')) msg = self.controller.applyCustom( int(self.cb_bestof.currentText()), self.cb_allkill.isChecked(), self.cb_solo.isChecked(), int(self.cb_minSets.currentText()), self.le_url_custom.text().strip()) self.statusBar().showMessage(msg) self.highlightApplyCustom(False) except Exception as e: module_logger.exception("message") finally: QApplication.restoreOverrideCursor() def resetdata_click(self): """Handle click to reset the data.""" QApplication.setOverrideCursor(Qt.WaitCursor) try: with self.tlock: msg = self.controller.resetData() self.statusBar().showMessage(msg) except Exception as e: module_logger.exception("message") finally: QApplication.restoreOverrideCursor() def refresh_click(self): """Handle click to refresh/load data from an URL.""" QApplication.setOverrideCursor(Qt.WaitCursor) try: url = self.le_url.lineEdit().text() with self.tlock: self.statusBar().showMessage(_('Reading {}...').format(url)) msg = self.controller.refreshData(url) self.statusBar().showMessage(msg) except Exception as e: module_logger.exception("message") finally: QApplication.restoreOverrideCursor() def openBrowser_click(self): """Handle request to open URL in browser.""" try: url = self.le_url.text() self.controller.openURL(url) except Exception as e: module_logger.exception("message") def updatenightbot_click(self): """Handle click to change nightbot command.""" try: self.statusBar().showMessage(_('Updating Nightbot Command...')) msg = self.controller.updateNightbotCommand() self.statusBar().showMessage(msg) except Exception as e: module_logger.exception("message") def updatetwitch_click(self): """Handle click to change twitch title.""" try: self.statusBar().showMessage(_('Updating Twitch Title...')) msg = self.controller.updateTwitchTitle() self.statusBar().showMessage(msg) except Exception as e: module_logger.exception("message") def resetscore_click(self, myteam=False): """Handle click to reset the score.""" try: self.statusBar().showMessage(_('Resetting Score...')) with self.tlock: matchDataWidget = self.matchDataTabWidget.currentWidget() for set_idx in range(self.max_no_sets): matchDataWidget.sl_score[set_idx].setValue(0) self.controller.matchControl.selectedMatch().setMapScore( set_idx, 0, overwrite=True) self.controller.autoSetNextMap() if myteam: matchDataWidget.sl_team.setValue(0) self.controller.matchControl.selectedMatch().setMyTeam(0) if not self.controller.resetWarning(): self.statusBar().showMessage('') except Exception as e: module_logger.exception("message") def highlightApplyCustom(self, highlight=True, force=False): if not force and not self.tlock.trigger(): return try: if self.applycustom_is_highlighted == highlight: return highlight except AttributeError: return False if highlight: myPalette = self.pb_applycustom.palette() myPalette.setColor(QPalette.Background, Qt.darkBlue) myPalette.setColor(QPalette.ButtonText, Qt.darkBlue) self.pb_applycustom.setPalette(myPalette) else: self.pb_applycustom.setPalette(self.defaultButtonPalette) self.applycustom_is_highlighted = highlight return highlight def logoDialog(self, team, matchDataWidget): """Open dialog for team logo.""" self.controller.logoManager.resetLogoChanged() self.mysubwindows['icons'] = SubwindowLogos() self.mysubwindows['icons'].createWindow(self, self.controller, team, matchDataWidget) self.mysubwindows['icons'].show() def resizeWindow(self): """Resize the window height to size hint.""" if (not self.isMaximized()): self.processEvents() self.resize(self.width(), self.sizeHint().height()) def processEvents(self): """Process ten PyQt5 events.""" for i in range(0, 10): self.app.processEvents() def restart(self, save=True): """Restart the main window.""" self._save = save self.close() self.app.exit(self.EXIT_CODE_REBOOT)
def createFormGroupTwitch(self): """Create forms for twitch.""" self.formGroupTwitch = QWidget() layout = QFormLayout() self.twitchChannel = MonitoredLineEdit() self.twitchChannel.textModified.connect(self.changed) self.twitchChannel.setText( scctool.settings.config.parser.get("Twitch", "channel")) self.twitchChannel.setAlignment(Qt.AlignCenter) self.twitchChannel.setPlaceholderText( _("Name of the Twitch channel that should be updated")) self.twitchChannel.setToolTip( _('The connected twitch user needs to have editor' ' rights for this channel.')) layout.addRow(QLabel("Twitch-Channel:"), self.twitchChannel) container = QHBoxLayout() self.twitchToken = MonitoredLineEdit() self.twitchToken.textModified.connect(self.changed) self.twitchToken.setText( scctool.settings.config.parser.get("Twitch", "oauth")) self.twitchToken.setAlignment(Qt.AlignCenter) self.twitchToken.setPlaceholderText( _("Press 'Get' to generate a token")) self.twitchToken.setEchoMode(QLineEdit.Password) self.twitchToken.setToolTip(_("Press 'Get' to generate a new token.")) container.addWidget(self.twitchToken) self.pb_getTwitch = QPushButton(_('Get')) self.pb_getTwitch.setFixedWidth(100) self.pb_getTwitch.clicked.connect( lambda: self.controller.authThread.requestToken('twitch')) container.addWidget(self.pb_getTwitch) layout.addRow(QLabel(_("Access-Token:")), container) container = QHBoxLayout() self.twitchTemplate = MonitoredLineEdit() self.twitchTemplate.textModified.connect(self.changed) self.twitchTemplate.setText( scctool.settings.config.parser.get("Twitch", "title_template")) self.twitchTemplate.setAlignment(Qt.AlignCenter) self.twitchTemplate.setPlaceholderText("(League) – (Team1) vs (Team2)") self.twitchTemplate.setToolTip( _('Available placeholders:') + " " + ', '.join(self.controller.placeholders.available())) completer = Completer(self.controller.placeholders.available(), self.twitchTemplate) self.twitchTemplate.setCompleter(completer) container.addWidget(self.twitchTemplate) button = QPushButton(_('Test')) button.setFixedWidth(100) button.clicked.connect( lambda: self.testPlaceholder(self.twitchTemplate.text())) container.addWidget(button) label = QLabel(_("Title Template:")) label.setFixedWidth(100) layout.addRow(label, container) container = QVBoxLayout() self.cb_set_game = QCheckBox(_("Set Game to 'StarCraft II'")) self.cb_set_game.setChecked( scctool.settings.config.parser.getboolean("Twitch", "set_game")) self.cb_set_game.stateChanged.connect(self.changed) container.addWidget(self.cb_set_game) label = QLabel(_("Options:") + " ") label.setMinimumWidth(120) layout.addRow(label, container) layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.formGroupTwitch.setLayout(layout)
class SubwindowConnections(QWidget): """Show connections settings sub window.""" current_tab = -1 def createWindow(self, mainWindow, tab=''): """Create window.""" try: parent = None super().__init__(parent) # self.setWindowFlags(Qt.WindowStaysOnTopHint) self.setWindowIcon(QIcon( scctool.settings.getResFile('twitch.png'))) self.setWindowModality(Qt.ApplicationModal) self.mainWindow = mainWindow self.passEvent = False self.controller = mainWindow.controller self.__dataChanged = False self.createButtonGroup() self.createTabs(tab) mainLayout = QVBoxLayout() mainLayout.addWidget(self.tabs) mainLayout.addLayout(self.buttonGroup) self.setLayout(mainLayout) self.resize( QSize(int(mainWindow.size().width() * 0.8), self.sizeHint().height())) relativeChange = QPoint(int(mainWindow.size().width() / 2), int(mainWindow.size().height() / 3)) -\ QPoint(int(self.size().width() / 2), int(self.size().height() / 3)) self.move(mainWindow.pos() + relativeChange) self.setWindowTitle(_("Twitch & Nightbot Connections")) except Exception: module_logger.exception("message") def createTabs(self, tab=''): """Create tabs.""" self.tabs = QTabWidget() self.createFormGroupTwitch() self.createFormGroupNightbot() # Add tabs self.tabs.addTab(self.formGroupTwitch, QIcon(scctool.settings.getResFile('twitch.png')), _("Twitch")) self.tabs.addTab(self.formGroupNightbot, QIcon(scctool.settings.getResFile('nightbot.ico')), _("Nightbot")) table = dict() table['twitch'] = 0 table['nightbot'] = 1 self.tabs.setCurrentIndex(table.get(tab, self.current_tab)) self.tabs.currentChanged.connect(self.tabChanged) @classmethod def tabChanged(cls, idx): """Save current tab index.""" cls.current_tab = idx def createFormGroupTwitch(self): """Create forms for twitch.""" self.formGroupTwitch = QWidget() layout = QFormLayout() self.twitchChannel = MonitoredLineEdit() self.twitchChannel.textModified.connect(self.changed) self.twitchChannel.setText( scctool.settings.config.parser.get("Twitch", "channel")) self.twitchChannel.setAlignment(Qt.AlignCenter) self.twitchChannel.setPlaceholderText( _("Name of the Twitch channel that should be updated")) self.twitchChannel.setToolTip( _('The connected twitch user needs to have editor' ' rights for this channel.')) layout.addRow(QLabel("Twitch-Channel:"), self.twitchChannel) container = QHBoxLayout() self.twitchToken = MonitoredLineEdit() self.twitchToken.textModified.connect(self.changed) self.twitchToken.setText( scctool.settings.config.parser.get("Twitch", "oauth")) self.twitchToken.setAlignment(Qt.AlignCenter) self.twitchToken.setPlaceholderText( _("Press 'Get' to generate a token")) self.twitchToken.setEchoMode(QLineEdit.Password) self.twitchToken.setToolTip(_("Press 'Get' to generate a new token.")) container.addWidget(self.twitchToken) self.pb_getTwitch = QPushButton(_('Get')) self.pb_getTwitch.setFixedWidth(100) self.pb_getTwitch.clicked.connect( lambda: self.controller.authThread.requestToken('twitch')) container.addWidget(self.pb_getTwitch) layout.addRow(QLabel(_("Access-Token:")), container) container = QHBoxLayout() self.twitchTemplate = MonitoredLineEdit() self.twitchTemplate.textModified.connect(self.changed) self.twitchTemplate.setText( scctool.settings.config.parser.get("Twitch", "title_template")) self.twitchTemplate.setAlignment(Qt.AlignCenter) self.twitchTemplate.setPlaceholderText("(League) – (Team1) vs (Team2)") self.twitchTemplate.setToolTip( _('Available placeholders:') + " " + ', '.join(self.controller.placeholders.available())) completer = Completer(self.controller.placeholders.available(), self.twitchTemplate) self.twitchTemplate.setCompleter(completer) container.addWidget(self.twitchTemplate) button = QPushButton(_('Test')) button.setFixedWidth(100) button.clicked.connect( lambda: self.testPlaceholder(self.twitchTemplate.text())) container.addWidget(button) label = QLabel(_("Title Template:")) label.setFixedWidth(100) layout.addRow(label, container) container = QVBoxLayout() self.cb_set_game = QCheckBox(_("Set Game to 'StarCraft II'")) self.cb_set_game.setChecked( scctool.settings.config.parser.getboolean("Twitch", "set_game")) self.cb_set_game.stateChanged.connect(self.changed) container.addWidget(self.cb_set_game) label = QLabel(_("Options:") + " ") label.setMinimumWidth(120) layout.addRow(label, container) layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.formGroupTwitch.setLayout(layout) def createFormGroupNightbot(self): """Create forms for nightbot.""" self.formGroupNightbot = QWidget() mainLayout = QVBoxLayout() tokenBox = QGroupBox("Access-Token") container = QHBoxLayout() self.nightbotToken = MonitoredLineEdit() self.nightbotToken.textModified.connect(self.changed) self.nightbotToken.setText( scctool.settings.config.parser.get("Nightbot", "token")) self.nightbotToken.setAlignment(Qt.AlignCenter) self.nightbotToken.setEchoMode(QLineEdit.Password) self.nightbotToken.setPlaceholderText( _("Press 'Get' to generate a token")) self.nightbotToken.setToolTip(_("Press 'Get' to generate a token.")) container.addWidget(self.nightbotToken) self.pb_getNightbot = QPushButton(_('Get')) self.pb_getNightbot.clicked.connect( lambda: self.controller.authThread.requestToken('nightbot')) self.pb_getNightbot.setFixedWidth(100) # self.pb_getNightbot.setEnabled(False) container.addWidget(self.pb_getNightbot) tokenBox.setLayout(container) mainLayout.addWidget(tokenBox, 0) # scroll area widget contents - layout self.scrollLayout = QVBoxLayout() self.scrollLayout.setDirection(QBoxLayout.BottomToTop) self.scrollLayout.addStretch(0) buttonLayout = QHBoxLayout() buttonLayout.addStretch(0) self.scrollLayout.addLayout(buttonLayout) # scroll area widget contents self.scrollWidget = QWidget() self.scrollWidget.setLayout(self.scrollLayout) # scroll area self.scrollArea = QScrollArea() self.scrollArea.setWidgetResizable(True) self.scrollArea.setWidget(self.scrollWidget) self.scrollArea.setFixedHeight(180) mainLayout.addWidget(self.scrollArea, 1) layout = QHBoxLayout() layout.addWidget(QLabel("")) addButton = QPushButton(_('Add Command')) addButton.clicked.connect(self.addCommand) layout.addWidget(addButton) mainLayout.addLayout(layout, 0) data = scctool.settings.nightbot_commands if len(data) == 0: self.addCommand() else: for cmd, msg in data.items(): self.addCommand(cmd, msg) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.formGroupNightbot.setLayout(mainLayout) def addCommand(self, cmd="", msg=""): """Add a nightbot command.""" if msg != "__DELETE__": dropbox = CommandDropBox(self.controller, cmd=cmd, msg=msg) dropbox.connect(self.changed) self.scrollLayout.insertWidget(1, dropbox) else: CommandDropBox.addDeletedCommand(cmd) def createButtonGroup(self): """Create buttons.""" try: layout = QHBoxLayout() layout.addWidget(QLabel("")) buttonCancel = QPushButton(_('Cancel')) buttonCancel.clicked.connect(self.closeWindow) layout.addWidget(buttonCancel) buttonSave = QPushButton(_('&Save && Close')) buttonSave.setToolTip(_("Shortcut: {}").format("Ctrl+S")) self.shortcut = QShortcut(QKeySequence("Ctrl+S"), self) self.shortcut.setAutoRepeat(False) self.shortcut.activated.connect(self.saveCloseWindow) buttonSave.clicked.connect(self.saveCloseWindow) layout.addWidget(buttonSave) self.buttonGroup = layout except Exception: module_logger.exception("message") def changed(self, *values): """Handle changed data.""" self.__dataChanged = True def saveData(self): """Save the data to config.""" if (self.__dataChanged): scctool.settings.config.parser.set( "Twitch", "channel", self.twitchChannel.text().strip()) scctool.settings.config.parser.set("Twitch", "oauth", self.twitchToken.text().strip()) scctool.settings.config.parser.set( "Twitch", "title_template", self.twitchTemplate.text().strip()) scctool.settings.config.parser.set( "Twitch", "set_game", str(self.cb_set_game.isChecked())) scctool.settings.config.parser.set( "Nightbot", "token", self.nightbotToken.text().strip()) self.__dataChanged = False self.controller.refreshButtonStatus() scctool.settings.nightbot_commands = CommandDropBox.getData() def saveCloseWindow(self): """Save and close window.""" self.saveData() self.closeWindow() def closeWindow(self): """Close window without save.""" self.passEvent = True self.close() def closeEvent(self, event): """Handle close event.""" try: if (not self.__dataChanged): CommandDropBox.clean() event.accept() return if (not self.passEvent): if (self.isMinimized()): self.showNormal() buttonReply = QMessageBox.question( self, _('Save data?'), _("Do you want to save the data?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.Yes: self.saveData() CommandDropBox.clean() event.accept() except Exception: module_logger.exception("message") def testPlaceholder(self, string): """Test placeholders.""" string = self.controller.placeholders.replace(string) QMessageBox.information(self, _("Output:"), string)
class CommandDropBox(QGroupBox): """QGroupBox for Nightbot command.""" _instances = set() _todelete = set() def __init__(self, controller, cmd="", msg="", parent=None): """Init dropbox.""" super().__init__(parent) self.controller = controller self._instances.add(weakref.ref(self)) self.ident = len(self._instances) layout = QHBoxLayout() self.command = MonitoredLineEdit() if not cmd: cmd = '' self.command.setText(cmd) self.command.setAlignment(Qt.AlignCenter) self.command.setPlaceholderText(("!command")) layout.addWidget(self.command) self.message = MonitoredLineEdit() self.message.setText(msg) self.message.setAlignment(Qt.AlignCenter) self.message.setPlaceholderText(_('message, e.g.,') + ' (URL)') self.message.setToolTip( _('Available placeholders:') + ' ' + ', '.join(self.controller.placeholders.available())) completer = Completer(self.controller.placeholders.available(), self.message) self.message.setCompleter(completer) layout.addWidget(self.message) self.pushButton1 = QPushButton(_('Test')) self.pushButton1.clicked.connect( lambda: self.testPlaceholder(self.message.text())) layout.addWidget(self.pushButton1) self.pushButton2 = QPushButton(_('Delete')) self.pushButton2.clicked.connect(self.remove) layout.addWidget(self.pushButton2) self.setLayout(layout) for ref in self._instances: obj = ref() if obj is not None: obj.setTitle() def connect(self, handler): """Connect handler.""" self.command.textModified.connect(handler) self.message.textModified.connect(handler) def setTitle(self): """Set the title.""" title = "Command {}".format(self.ident) super().setTitle(title) self.pushButton2.setDisabled(len(self._instances) == 1) def adjustIdent(self, removedIdent): """Adjust ident.""" if removedIdent < self.ident: self.ident -= 1 self.setTitle() def remove(self): """Remove command.""" self.parent().layout().removeWidget(self) cmd = self.command.text().strip() if cmd: self._todelete.add(cmd) self.deleteLater() self._instances.remove(weakref.ref(self)) for ref in self._instances: obj = ref() if obj is not None: obj.adjustIdent(self.ident) def testPlaceholder(self, string): """Test placeholders.""" string = self.controller.placeholders.replace(string) QMessageBox.information(self, _("Output:"), string) @classmethod def addDeletedCommand(cls, cmd): """Delete command to to-delete-list.""" cls._todelete.add(cmd.strip()) @classmethod def getData(cls): """Return commands.""" data = dict() for cmd in cls._todelete: data[cmd] = "__DELETE__" for inst_ref in cls._instances: inst = inst_ref() if inst is not None: cmd = inst.command.text().strip() msg = inst.message.text().strip() if cmd and msg: data[cmd] = msg return data @classmethod def clean(cls): """Clean command.""" cls._instances = set() cls._todelete = set()
def createFormGroupNightbot(self): """Create forms for nightbot.""" self.formGroupNightbot = QWidget() mainLayout = QVBoxLayout() tokenBox = QGroupBox("Access-Token") container = QHBoxLayout() self.nightbotToken = MonitoredLineEdit() self.nightbotToken.textModified.connect(self.changed) self.nightbotToken.setText( scctool.settings.config.parser.get("Nightbot", "token")) self.nightbotToken.setAlignment(Qt.AlignCenter) self.nightbotToken.setEchoMode(QLineEdit.Password) self.nightbotToken.setPlaceholderText( _("Press 'Get' to generate a token")) self.nightbotToken.setToolTip(_("Press 'Get' to generate a token.")) container.addWidget(self.nightbotToken) self.pb_getNightbot = QPushButton(_('Get')) self.pb_getNightbot.clicked.connect( lambda: self.controller.authThread.requestToken('nightbot')) self.pb_getNightbot.setFixedWidth(100) # self.pb_getNightbot.setEnabled(False) container.addWidget(self.pb_getNightbot) tokenBox.setLayout(container) mainLayout.addWidget(tokenBox, 0) # scroll area widget contents - layout self.scrollLayout = QVBoxLayout() self.scrollLayout.setDirection(QBoxLayout.BottomToTop) self.scrollLayout.addStretch(0) buttonLayout = QHBoxLayout() buttonLayout.addStretch(0) self.scrollLayout.addLayout(buttonLayout) # scroll area widget contents self.scrollWidget = QWidget() self.scrollWidget.setLayout(self.scrollLayout) # scroll area self.scrollArea = QScrollArea() self.scrollArea.setWidgetResizable(True) self.scrollArea.setWidget(self.scrollWidget) self.scrollArea.setFixedHeight(180) mainLayout.addWidget(self.scrollArea, 1) layout = QHBoxLayout() layout.addWidget(QLabel("")) addButton = QPushButton(_('Add Command')) addButton.clicked.connect(self.addCommand) layout.addWidget(addButton) mainLayout.addLayout(layout, 0) data = scctool.settings.nightbot_commands if len(data) == 0: self.addCommand() else: for cmd, msg in data.items(): self.addCommand(cmd, msg) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.formGroupNightbot.setLayout(mainLayout)
def createOcrBox(self): """Create forms for OCR.""" self.ocrBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox( _("Optical Character Recognition for" " Automatic Setting of Ingame Score")) layout = QGridLayout() self.cb_useocr = QCheckBox(" " + _("Activate Optical Character Recognition")) self.cb_useocr.setChecked( scctool.settings.config.parser.getboolean("SCT", "use_ocr")) self.cb_useocr.stateChanged.connect(self.changed) self.tesseract = MonitoredLineEdit() self.tesseract.setText( scctool.settings.config.parser.get("SCT", "tesseract")) self.tesseract.textModified.connect(self.changed) # self.tesseract.setAlignment(Qt.AlignCenter) self.tesseract.setPlaceholderText( "C:\\Program Files (x86)\\Tesseract-OCR\\tesseract") self.tesseract.setReadOnly(True) self.tesseract.setToolTip(_('Tesseract-OCR Executable')) self.browse = QPushButton(_("Browse...")) self.browse.clicked.connect(self.selectTesseract) text = _( "Sometimes the order of players given by the SC2-Client-API" " differs from the order in the Observer-UI resulting in a" " swapped match score. To correct this via Optical Character" " Recognition you have to download {} and install and select the" " exectuable below, if it is not detected automatically.") url = 'https://github.com/UB-Mannheim/tesseract' + \ '/wiki#tesseract-at-ub-mannheim' href = "<a href='{}'>" + "Tesseract-OCR" + "</a>" href = href.format(url) label = QLabel(text.format(href)) label.setAlignment(Qt.AlignJustify) label.setOpenExternalLinks(True) label.setWordWrap(True) label.setMargin(5) layout.addWidget(label, 1, 0, 1, 2) layout.addWidget(self.cb_useocr, 0, 0, 1, 2) layout.addWidget(QLabel(_("Tesseract-OCR Executable") + ":"), 2, 0) layout.addWidget(self.tesseract, 3, 0) layout.addWidget(self.browse, 3, 1) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.ocrBox.setLayout(mainLayout) if (not scctool.settings.windows): self.cb_useocr.setEnabled(False) self.cb_useocr.setAttribute(Qt.WA_AlwaysShowToolTips) self.cb_useocr.setToolTip( _("This feature is only available in Windows.")) self.tesseract.setEnabled(False) self.tesseract.setAttribute(Qt.WA_AlwaysShowToolTips) self.tesseract.setToolTip( _("This feature is only available in Windows.")) self.browse.setEnabled(False) self.browse.setAttribute(Qt.WA_AlwaysShowToolTips) self.browse.setToolTip( _("This feature is only available in Windows."))
def createSC2ClientAPIBox(self): """Create form for SC2 Client API config.""" self.clientapiBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("SC2 Client API Address")) layout = QGridLayout() self.cb_usesc2listener = QCheckBox( " " + _("Listen to SC2 Client API running" " on a different PC in the network.")) self.cb_usesc2listener.setChecked( scctool.settings.config.parser.getboolean( "SCT", "sc2_network_listener_enabled")) self.cb_usesc2listener.stateChanged.connect(self.changed) self.listener_address = MonitoredLineEdit() self.listener_address.setAlignment(Qt.AlignCenter) self.listener_address.setText( scctool.settings.config.parser.get("SCT", "sc2_network_listener_address")) self.listener_address.textModified.connect(self.changed) # self.tesseract.setAlignment(Qt.AlignCenter) self.listener_address.setPlaceholderText("[Your SC2 PC IP]:6119") self.listener_address.setToolTip( _('IP address and port of machine running SC2.')) ip_port = ( r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)" + r"{3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]):[0-9]+$") self.listener_address.setValidator(QRegExpValidator(QRegExp(ip_port))) self.test_listener = QPushButton(" " + _("Test SC2 Client API Connection") + " ") self.test_listener.clicked.connect(self.testClientAPI) text = _("Activate this option if you are using a two computer " "setup with StarCraft Casting Tool running on a different" " PC than your SC2 client. Open the Battle.net launcher " "on the latter PC, click 'Options', 'Game Settings', and " "under SC2, check 'Additional Command Line Arguments', and " "enter '-clientapi 6119'. Finally set as network" " address below: '[Your SC2 PC IP]:6119'.") label = QLabel(text) label.setAlignment(Qt.AlignJustify) label.setOpenExternalLinks(True) label.setWordWrap(True) label.setMargin(5) layout.addWidget(label, 1, 0, 1, 3) layout.addWidget(self.cb_usesc2listener, 0, 0, 1, 3) layout.addWidget(QLabel(_("Network Address") + ": "), 3, 0) layout.addWidget(self.listener_address, 3, 1) layout.addWidget(self.test_listener, 3, 2) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.clientapiBox.setLayout(mainLayout)
class SubwindowMisc(QWidget): """Show subwindow with miscellaneous settings.""" current_tab = -1 def createWindow(self, mainWindow, tab=''): """Create subwindow with miscellaneous settings.""" try: parent = None super().__init__(parent) # self.setWindowFlags(Qt.WindowStaysOnTopHint) self.setWindowIcon( QIcon(scctool.settings.getResFile('settings.png'))) self.setWindowModality(Qt.ApplicationModal) self.mainWindow = mainWindow self.passEvent = False self.controller = mainWindow.controller self.__dataChanged = False self.createButtonGroup() self.createTabs(tab) mainLayout = QVBoxLayout() mainLayout.addWidget(self.tabs) mainLayout.addLayout(self.buttonGroup) self.setLayout(mainLayout) self.resize( QSize(int(mainWindow.size().width() * 0.9), self.sizeHint().height())) relativeChange = QPoint(int(mainWindow.size().width() / 2), int(mainWindow.size().height() / 3))\ - QPoint(int(self.size().width() / 2), int(self.size().height() / 3)) self.move(mainWindow.pos() + relativeChange) self.setWindowTitle(_("Miscellaneous Settings")) except Exception: module_logger.exception("message") def createTabs(self, tab=''): """Create tabs.""" self.tabs = QTabWidget() self.createMapsBox() self.createFavBox() self.createAliasBox() self.createOcrBox() self.createAlphaBox() self.createSC2ClientAPIBox() self.createAligulacTab() self.createCounterTab() # Add tabs self.tabs.addTab(self.mapsBox, _("Map Manager")) self.tabs.addTab(self.favBox, _("Favorites")) self.tabs.addTab(self.aliasBox, _("Alias")) self.tabs.addTab(self.ocrBox, _("OCR")) self.tabs.addTab(self.alphaBox, _("AlphaTL && Ingame Score")) self.tabs.addTab(self.clientapiBox, _("SC2 Client API")) self.tabs.addTab(self.aligulacTab, _("Aligulac")) self.tabs.addTab(self.counterTab, _("Countdown && Ticker")) table = dict() table['mapmanager'] = 0 table['favorites'] = 1 table['alias'] = 2 table['ocr'] = 3 table['alphatl'] = 4 table['sc2clientapi'] = 5 table['aligulac'] = 6 table['counter'] = 7 self.tabs.setCurrentIndex(table.get(tab, SubwindowMisc.current_tab)) self.tabs.currentChanged.connect(self.tabChanged) @classmethod def tabChanged(cls, idx): """Save the current tab index.""" SubwindowMisc.current_tab = idx def changed(self): """Handle changes.""" self.__dataChanged = True def createAlphaBox(self): """Create Alpha QWidget.""" self.alphaBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("AlphaTL")) layout = QHBoxLayout() self.cb_trans_banner = QCheckBox( " " + _("Download transparent Banner of the Match")) self.cb_trans_banner.setChecked( scctool.settings.config.parser.getboolean( "SCT", "transparent_match_banner")) self.cb_trans_banner.stateChanged.connect(self.changed) layout.addWidget(self.cb_trans_banner) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Set Ingame Score Task")) layout = QVBoxLayout() self.cb_ctrlx = QCheckBox(" " + _('Automatically press Ctrl+X to apply the' ' correct player order ingame')) self.cb_ctrlx.setToolTip( _("This will ensure that the player of the first team is always" " on the left/top in the ingame Observer UI.")) self.cb_ctrlx.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlX")) self.cb_ctrlx.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrlx) self.cb_ctrln = QCheckBox(" " + _('Automatically press Ctrl+N before' ' OCR to display player names')) self.cb_ctrln.setToolTip( _("This is recommended for Standard and Gawliq Observer UI.")) self.cb_ctrln.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlN")) self.cb_ctrln.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrln) self.cb_ctrlshifts = QCheckBox( " " + _('Automatically press Ctrl+Shift+S to display' ' the ingame score')) self.cb_ctrlshifts.setToolTip( _("Ctrl+Shift+S is needed for the WCS-Gameheart Oberserver" " Overlay, but disables the sound for other overlays.")) self.cb_ctrlshifts.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlShiftS")) self.cb_ctrlshifts.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrlshifts) self.cb_ctrlshiftc = QCheckBox( " " + _('Automatically press Ctrl+Shift+C to toogle the clan tag')) self.cb_ctrlshiftc.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlShiftC")) self.cb_ctrlshiftc.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrlshiftc) container = QHBoxLayout() self.cb_ctrlshiftr = QComboBox() self.cb_ctrlshiftr.addItem("0") self.cb_ctrlshiftr.addItem("1") self.cb_ctrlshiftr.addItem("2") try: self.cb_ctrlshiftr.setCurrentIndex( scctool.settings.config.parser.getint("SCT", "CtrlShiftR")) except Exception: self.cb_ctrlshiftr.setCurrentIndex(0) self.cb_ctrlshiftr.setMaximumWidth(40) self.cb_ctrlshiftr.currentIndexChanged.connect(self.changed) container.addWidget( QLabel( _('Automatically press Ctrl+Shift+R to toogle the race icon ')) ) container.addWidget(self.cb_ctrlshiftr) container.addWidget(QLabel(_(' time(s)'))) layout.addLayout(container) self.cb_blacklist = QCheckBox(" " + _('Activate Blacklist for' ' Ingame Score')) self.cb_blacklist.setChecked( scctool.settings.config.parser.getboolean("SCT", "blacklist_on")) self.cb_blacklist.stateChanged.connect(self.changed) layout.addWidget(self.cb_blacklist) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Blacklist for Ingame Score")) layout = QVBoxLayout() blacklistDesc = _("Enter your SC2 client usernames to deactivate" " automatically setting the ingame score and" " toogling the production tab when you are playing" " yourself. Replays are exempt.") label = QLabel(blacklistDesc) label.setAlignment(Qt.AlignJustify) label.setWordWrap(True) layout.addWidget(label) self.list_blacklist = ListTable(4, scctool.settings.config.getBlacklist()) self.list_blacklist.dataModified.connect(self.changed) self.list_blacklist.setFixedHeight(50) layout.addWidget(self.list_blacklist) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.alphaBox.setLayout(mainLayout) def createFavBox(self): """Create favorites box.""" self.favBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("Players")) layout = QHBoxLayout() self.list_favPlayers = ListTable( 4, scctool.settings.config.getMyPlayers()) self.list_favPlayers.dataModified.connect(self.changed) self.list_favPlayers.setFixedHeight(150) layout.addWidget(self.list_favPlayers) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Teams")) layout = QVBoxLayout() self.list_favTeams = ListTable(3, scctool.settings.config.getMyTeams()) self.list_favTeams.dataModified.connect(self.changed) self.list_favTeams.setFixedHeight(100) layout.addWidget(self.list_favTeams) self.cb_swapTeams = QCheckBox( _('Swap my favorite team always to the left')) self.cb_swapTeams.setChecked( scctool.settings.config.parser.getboolean("SCT", "swap_myteam")) self.cb_swapTeams.stateChanged.connect(self.changed) layout.addWidget(self.cb_swapTeams) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.favBox.setLayout(mainLayout) def createAliasBox(self): """Create favorites box.""" self.aliasBox = QWidget() mainLayout = QGridLayout() aliasDesc = _( 'Player, team, and league aliases are replaced by the actual name when' + ' encountered by the match grabber. Additionally, SC2 player' + ' names listed as aliases are replaced in the intros' + ' and used to identify players by the automatic' + ' background tasks "Auto Score Update" and "Set Ingame Score".') label = QLabel(aliasDesc) label.setAlignment(Qt.AlignJustify) label.setWordWrap(True) mainLayout.addWidget(label, 1, 0, 1, 3) box = QGroupBox(_("Player Aliases")) layout = QVBoxLayout() self.list_aliasPlayers = AliasTreeView(self) self.list_aliasPlayers.aliasRemoved.connect( self.controller.aliasManager.removePlayerAlias) layout.addWidget(self.list_aliasPlayers) addButton = QPushButton(_("Add Alias")) addButton.clicked.connect( lambda: self.addAlias(self.list_aliasPlayers, _('Player Name'))) layout.addWidget(addButton) box.setLayout(layout) mainLayout.addWidget(box, 0, 0) box = QGroupBox(_("Team Aliases")) layout = QVBoxLayout() self.list_aliasTeams = AliasTreeView(self) self.list_aliasTeams.aliasRemoved.connect( self.controller.aliasManager.removeTeamAlias) layout.addWidget(self.list_aliasTeams) addButton = QPushButton(_("Add Alias")) addButton.clicked.connect( lambda: self.addAlias(self.list_aliasTeams, _('Team Name'))) layout.addWidget(addButton) box.setLayout(layout) mainLayout.addWidget(box, 0, 1) box = QGroupBox(_("League Aliases")) layout = QVBoxLayout() self.list_aliasLeagues = AliasTreeView(self) self.list_aliasLeagues.aliasRemoved.connect( self.controller.aliasManager.removeLeagueAlias) layout.addWidget(self.list_aliasLeagues) addButton = QPushButton(_("Add Alias")) addButton.clicked.connect( lambda: self.addAlias(self.list_aliasLeagues, _('League Name'))) layout.addWidget(addButton) box.setLayout(layout) mainLayout.addWidget(box, 0, 2) alias_list = self.controller.aliasManager.playerAliasList() for player, aliases in alias_list.items(): self.list_aliasPlayers.insertAliasList(player, aliases) alias_list = self.controller.aliasManager.teamAliasList() for league, aliases in alias_list.items(): self.list_aliasTeams.insertAliasList(league, aliases) alias_list = self.controller.aliasManager.leagueAliasList() for league, aliases in alias_list.items(): self.list_aliasLeagues.insertAliasList(league, aliases) self.aliasBox.setLayout(mainLayout) def addAlias(self, widget, scope, name=""): """Add an alias.""" name, ok = QInputDialog.getText(self, scope, scope + ':', text=name) if not ok: return name = name.strip() alias, ok = QInputDialog.getText(self, _('Alias'), _('Alias of {}').format(name) + ':', text="") alias = alias.strip() if not ok: return try: if widget == self.list_aliasPlayers: self.controller.aliasManager.addPlayerAlias(name, alias) elif widget == self.list_aliasTeams: self.controller.aliasManager.addTeamAlias(name, alias) elif widget == self.list_aliasLeagues: self.controller.aliasManager.addLeagueAlias(name, alias) widget.insertAlias(name, alias, True) except Exception as e: module_logger.exception("message") QMessageBox.critical(self, _("Error"), str(e)) def createSC2ClientAPIBox(self): """Create form for SC2 Client API config.""" self.clientapiBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("SC2 Client API Address")) layout = QGridLayout() self.cb_usesc2listener = QCheckBox( " " + _("Listen to SC2 Client API running" " on a different PC in the network.")) self.cb_usesc2listener.setChecked( scctool.settings.config.parser.getboolean( "SCT", "sc2_network_listener_enabled")) self.cb_usesc2listener.stateChanged.connect(self.changed) self.listener_address = MonitoredLineEdit() self.listener_address.setAlignment(Qt.AlignCenter) self.listener_address.setText( scctool.settings.config.parser.get("SCT", "sc2_network_listener_address")) self.listener_address.textModified.connect(self.changed) # self.tesseract.setAlignment(Qt.AlignCenter) self.listener_address.setPlaceholderText("[Your SC2 PC IP]:6119") self.listener_address.setToolTip( _('IP address and port of machine running SC2.')) ip_port = ( r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)" + r"{3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]):[0-9]+$") self.listener_address.setValidator(QRegExpValidator(QRegExp(ip_port))) self.test_listener = QPushButton(" " + _("Test SC2 Client API Connection") + " ") self.test_listener.clicked.connect(self.testClientAPI) text = _("Activate this option if you are using a two computer " "setup with StarCraft Casting Tool running on a different" " PC than your SC2 client. Open the Battle.net launcher " "on the latter PC, click 'Options', 'Game Settings', and " "under SC2, check 'Additional Command Line Arguments', and " "enter '-clientapi 6119'. Finally set as network" " address below: '[Your SC2 PC IP]:6119'.") label = QLabel(text) label.setAlignment(Qt.AlignJustify) label.setOpenExternalLinks(True) label.setWordWrap(True) label.setMargin(5) layout.addWidget(label, 1, 0, 1, 3) layout.addWidget(self.cb_usesc2listener, 0, 0, 1, 3) layout.addWidget(QLabel(_("Network Address") + ": "), 3, 0) layout.addWidget(self.listener_address, 3, 1) layout.addWidget(self.test_listener, 3, 2) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.clientapiBox.setLayout(mainLayout) def testClientAPI(self): """Test for connection to sc2 client api.""" QApplication.setOverrideCursor(Qt.WaitCursor) address = self.listener_address.text().strip() url = "http://{}/ui".format(address) try: r = requests.get(url, timeout=10) r.raise_for_status() successfull = True except Exception: successfull = False module_logger.error("message") finally: QApplication.restoreOverrideCursor() title = _("Connection Test") if successfull: QMessageBox.information( self, title, _('Connection to SC2 client API established!')) else: QMessageBox.warning( self, title, _('Unable to connect to SC2 client API.' ' Please make sure that SC2 is currently' ' running on that machine.')) def createOcrBox(self): """Create forms for OCR.""" self.ocrBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox( _("Optical Character Recognition for" " Automatic Setting of Ingame Score")) layout = QGridLayout() self.cb_useocr = QCheckBox(" " + _("Activate Optical Character Recognition")) self.cb_useocr.setChecked( scctool.settings.config.parser.getboolean("SCT", "use_ocr")) self.cb_useocr.stateChanged.connect(self.changed) self.tesseract = MonitoredLineEdit() self.tesseract.setText( scctool.settings.config.parser.get("SCT", "tesseract")) self.tesseract.textModified.connect(self.changed) # self.tesseract.setAlignment(Qt.AlignCenter) self.tesseract.setPlaceholderText( "C:\\Program Files (x86)\\Tesseract-OCR\\tesseract") self.tesseract.setReadOnly(True) self.tesseract.setToolTip(_('Tesseract-OCR Executable')) self.browse = QPushButton(_("Browse...")) self.browse.clicked.connect(self.selectTesseract) text = _( "Sometimes the order of players given by the SC2-Client-API" " differs from the order in the Observer-UI resulting in a" " swapped match score. To correct this via Optical Character" " Recognition you have to download {} and install and select the" " exectuable below, if it is not detected automatically.") url = 'https://github.com/UB-Mannheim/tesseract' + \ '/wiki#tesseract-at-ub-mannheim' href = "<a href='{}'>" + "Tesseract-OCR" + "</a>" href = href.format(url) label = QLabel(text.format(href)) label.setAlignment(Qt.AlignJustify) label.setOpenExternalLinks(True) label.setWordWrap(True) label.setMargin(5) layout.addWidget(label, 1, 0, 1, 2) layout.addWidget(self.cb_useocr, 0, 0, 1, 2) layout.addWidget(QLabel(_("Tesseract-OCR Executable") + ":"), 2, 0) layout.addWidget(self.tesseract, 3, 0) layout.addWidget(self.browse, 3, 1) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.ocrBox.setLayout(mainLayout) if (not scctool.settings.windows): self.cb_useocr.setEnabled(False) self.cb_useocr.setAttribute(Qt.WA_AlwaysShowToolTips) self.cb_useocr.setToolTip( _("This feature is only available in Windows.")) self.tesseract.setEnabled(False) self.tesseract.setAttribute(Qt.WA_AlwaysShowToolTips) self.tesseract.setToolTip( _("This feature is only available in Windows.")) self.browse.setEnabled(False) self.browse.setAttribute(Qt.WA_AlwaysShowToolTips) self.browse.setToolTip( _("This feature is only available in Windows.")) def selectTesseract(self): """Create forms for tesseract.""" old_exe = self.tesseract.text() default = scctool.settings.config.findTesserAct(old_exe) exe, ok = QFileDialog.getOpenFileName( self, _("Select Tesseract-OCR Executable"), default, _("Tesseract-OCR Executable") + " (tesseract.exe);; " + _("Executable") + " (*.exe);; " + _("All files") + " (*)") if (ok and exe != old_exe): self.tesseract.setText(exe) self.changed() def createAligulacTab(self): """Create the aligulac tab.""" self.aligulacTab = QWidget() layout = QGridLayout() self.aligulacTreeview = AligulacTreeView( self, self.controller.aligulacManager) layout.addWidget(self.aligulacTreeview, 0, 0, 3, 1) self.pb_addAligulacID = QPushButton(_("Add Aligluac ID")) self.pb_addAligulacID.clicked.connect( lambda x, self=self: self.addAligulacID()) layout.addWidget(self.pb_addAligulacID, 1, 1) self.pb_removeAligulacID = QPushButton(_("Remove Aligulac ID")) self.pb_removeAligulacID.clicked.connect(self.removeAligulacID) layout.addWidget(self.pb_removeAligulacID, 2, 1) layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Minimum), 0, 1) self.aligulacTab.setLayout(layout) def addAligulacID(self, name='', aligulac_id=1): """Add an aligulac ID.""" text, ok = QInputDialog.getText(self, _('Player Name'), _('Player Name') + ':', text=name) text = text.strip() if not ok or not text: return aligulac_id, ok = QInputDialog.getInt(self, _('Aligulac ID'), _('Aligulac ID') + ':', value=aligulac_id, min=1) if not ok: return self.aligulacTreeview.insertItem(text, aligulac_id) def removeAligulacID(self): """Remove an selected aligulac ID.""" self.aligulacTreeview.removeSelected() def createCounterTab(self): """Create the aligulac tab.""" self.counterTab = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("Countdown")) layout = QFormLayout() self.le_countdown_replacement = QLineEdit() self.le_countdown_replacement.setText( scctool.settings.config.parser.get("Countdown", "replacement")) self.le_countdown_replacement.textChanged.connect(self.changed) layout.addRow(QLabel(_('Replacement Text')), self.le_countdown_replacement) self.cb_counter_matchgrabber_update = QCheckBox('') self.cb_counter_matchgrabber_update.setChecked( scctool.settings.config.parser.getboolean("Countdown", "matchgrabber_update")) self.cb_counter_matchgrabber_update.stateChanged.connect(self.changed) layout.addRow(QLabel(_('Update Static Countdown via MatchGrabber')), self.cb_counter_matchgrabber_update) self.counter_pretext = QPlainTextEdit() self.counter_pretext.setPlainText( scctool.settings.config.parser.get("Countdown", "pre_txt")) self.counter_pretext.textChanged.connect(self.changed) self.counter_posttext = QPlainTextEdit() self.counter_posttext.setPlainText( scctool.settings.config.parser.get("Countdown", "post_txt")) self.counter_posttext.textChanged.connect(self.changed) layout.addRow(QLabel(_('Pre-Text (in countdown.txt)')), self.counter_pretext) layout.addRow(QLabel(_('Post-Text (in countdown.txt)')), self.counter_posttext) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Ticker")) layout = QFormLayout() box.setLayout(layout) self.ticker_pretext = QLineEdit() self.ticker_pretext.setText( scctool.settings.config.parser.get("Ticker", "prefix")) self.ticker_pretext.textChanged.connect(self.changed) layout.addRow(QLabel(_('Prefix text (in ticker.txt)')), self.ticker_pretext) mainLayout.addWidget(box) self.counterTab.setLayout(mainLayout) def createMapsBox(self): """Create box for map manager.""" self.mapsize = 300 self.mapsBox = QWidget() layout = QGridLayout() self.maplist = QListWidget() self.maplist.setSortingEnabled(True) for sc2map in scctool.settings.maps: self.maplist.addItem(QListWidgetItem(sc2map)) self.maplist.setCurrentItem(self.maplist.item(0)) self.maplist.currentItemChanged.connect(self.changePreview) # self.maplist.setFixedHeight(self.mapsize) self.maplist.setMinimumWidth(150) layout.addWidget(self.maplist, 0, 1, 2, 1) self.mapPreview = QLabel() self.mapPreview.setFixedWidth(self.mapsize) self.mapPreview.setFixedHeight(self.mapsize) self.mapPreview.setAlignment(Qt.AlignCenter) layout.addWidget(self.mapPreview, 0, 0) self.mapInfo = QLabel() self.mapInfo.setIndent(10) layout.addWidget(self.mapInfo, 1, 0) self.pb_addMapLiquipedia = QPushButton(_("Add from Liquipedia")) self.pb_addMapLiquipedia.clicked.connect(self.addFromLquipedia) self.pb_addMap = QPushButton(_("Add from File")) self.pb_addMap.clicked.connect(self.addMap) self.pb_renameMap = QPushButton(_("Rename")) self.pb_renameMap.clicked.connect(self.renameMap) self.pb_changeMap = QPushButton(_("Change Image")) self.pb_changeMap.clicked.connect(self.changeMap) self.pb_removeMap = QPushButton(_("Remove")) self.pb_removeMap.clicked.connect(self.deleteMap) self.sc_removeMap = QShortcut(QKeySequence("Del"), self.maplist) self.sc_removeMap.setAutoRepeat(False) self.sc_removeMap.setContext(Qt.WidgetWithChildrenShortcut) self.sc_removeMap.activated.connect(self.deleteMap) self.cb_newMapsPrompt = QCheckBox( _('Prompt to download new ladders maps.')) self.cb_newMapsPrompt.setChecked( scctool.settings.config.parser.getboolean("SCT", "new_maps_prompt")) self.cb_newMapsPrompt.stateChanged.connect(self.changed) self.pb_downloadLadderMaps = QPushButton(_("Download Ladder Maps")) self.pb_downloadLadderMaps.clicked.connect(self.downloadLadderMaps) box = QWidget() container = QHBoxLayout() container.addWidget(self.pb_addMapLiquipedia, 0) container.addWidget(self.pb_addMap, 0) container.addWidget(QLabel(), 1) container.addWidget(self.pb_downloadLadderMaps, 0) container.addWidget(QLabel(), 1) container.addWidget(self.pb_renameMap, 0) container.addWidget(self.pb_changeMap, 0) container.addWidget(self.pb_removeMap, 0) box.setLayout(container) layout.addWidget(box, 2, 0, 1, 2) layout.addWidget(self.cb_newMapsPrompt, 3, 0, 1, 1) layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), 3, 2, 1, 2) layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), 4, 0, 1, 2) self.changePreview() self.mapsBox.setLayout(layout) def renameMap(self): """Rename maps.""" item = self.maplist.currentItem() mapname = item.text() text, ok = QInputDialog.getText(self, _('Map Name'), _('Map Name') + ':', text=mapname) if not ok: return text = text.strip() if (text == mapname): return if text.lower() == 'tbd': QMessageBox.critical( self, _("Error"), _('"{}" is not a valid map name.').format(text)) return if (text in scctool.settings.maps): buttonReply = QMessageBox.warning( self, _("Duplicate Entry"), _("Map is already in list! Overwrite?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.No: return self.controller.addMap(self.controller.getMapImg(mapname, True), text) self.controller.deleteMap(mapname) item.setText(text) def changeMap(self): """Change a map.""" current_map = self.maplist.currentItem().text() fileName, ok = QFileDialog.getOpenFileName( self, _("Select Map Image (> 500x500px recommended)"), "", _("Supported Images") + " (*.png *.jpg *.jpeg)") if ok: base = os.path.basename(fileName) name, __ = os.path.splitext(base) name = name.replace("_", " ") self.controller.deleteMap(current_map) self.controller.addMap(fileName, current_map) self.changePreview() def addMap(self): """Add a map.""" fileName, ok = QFileDialog.getOpenFileName( self, _("Select Map Image (> 500x500px recommended)"), "", _("Supported Images") + " (*.png *.jpg *.jpeg)") if ok: base = os.path.basename(fileName) name, __ = os.path.splitext(base) name = name.replace("_", " ") map_name, ok = QInputDialog.getText(self, _('Map Name'), _('Map Name') + ':', text=name) map_name = map_name.strip() if ok: if map_name.lower() == 'tbd': QMessageBox.critical( self, _("Error"), _('"{}" is not a valid map name.').format(map_name)) return if (map_name in scctool.settings.maps): buttonReply = QMessageBox.warning( self, _("Duplicate Entry"), _("Map is already in list! Overwrite?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.No: return else: self.controller.deleteMap(map_name) self.controller.addMap(fileName, map_name) items = self.maplist.findItems(map_name, Qt.MatchExactly) if len(items) == 0: item = QListWidgetItem(map_name) self.maplist.addItem(item) self.maplist.setCurrentItem(item) else: self.maplist.setCurrentItem(items[0]) self.changePreview() def downloadLadderMaps(self): players_per_team, ok = QInputDialog.getItem( self, _('Select the type of ladder maps to download'), _('Please select a map type') + ':', ['1vs1', '2vs2', '3vs3', '4vs4'], editable=False) players_per_team = int(players_per_team[0]) found_a_map = False for sc2map in LiquipediaGrabber().get_ladder_mappool(players_per_team): if not sc2map in scctool.settings.maps: found_a_map = True self.controller.autoDownloadMap(sc2map, self) scctool.settings.maps.append(sc2map) items = self.maplist.findItems(sc2map, Qt.MatchExactly) if len(items) == 0: item = QListWidgetItem(sc2map) self.maplist.addItem(item) self.maplist.setCurrentItem(item) else: self.maplist.setCurrentItem(items[0]) self.changePreview() if not found_a_map: QMessageBox.information( self, _("No missing map"), _('All of the current ladder maps are already present.')) def addFromLquipedia(self): """Add a map from Liquipedia.""" grabber = LiquipediaGrabber() search_str = '' while True: search_str, ok = QInputDialog.getText(self, _('Map Name'), _('Map Name') + ':', text=search_str) search_str.strip() try: if ok and search_str: if search_str.lower() == 'tbd': QMessageBox.critical( self, _("Error"), _('"{}" is not a valid map name.').format( search_str)) continue try: QApplication.setOverrideCursor(Qt.WaitCursor) sc2map = grabber.get_map(search_str) except MapNotFound: QMessageBox.critical( self, _("Map not found"), _('"{}" was not found on Liquipedia.').format( search_str)) continue finally: QApplication.restoreOverrideCursor() map_name = sc2map.get_name() if (map_name in scctool.settings.maps): buttonReply = QMessageBox.warning( self, _("Duplicate Entry"), _("Map {} is already in list! Overwrite?".format( map_name)), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.No: break else: self.controller.deleteMap(map_name) try: QApplication.setOverrideCursor(Qt.WaitCursor) images = grabber.get_images(sc2map.get_map_images()) image = "" for size in sorted(images): if not image or size <= 2500 * 2500: image = images[size] url = grabber._base_url + image downloader = MapDownloader(self, map_name, url) downloader.download() if map_name not in scctool.settings.maps: scctool.settings.maps.append(map_name) items = self.maplist.findItems(map_name, Qt.MatchExactly) if len(items) == 0: item = QListWidgetItem(map_name) self.maplist.addItem(item) self.maplist.setCurrentItem(item) else: self.maplist.setCurrentItem(items[0]) self.changePreview() except Exception: raise finally: QApplication.restoreOverrideCursor() except Exception as e: module_logger.exception("message") QMessageBox.critical(self, _("Error"), str(e)) break def deleteMap(self): """Delete a map.""" item = self.maplist.currentItem() mapname = item.text() buttonReply = QMessageBox.question( self, _('Delete map?'), _("Delete '{}' permanently?").format(mapname), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.Yes: self.controller.deleteMap(mapname) self.maplist.takeItem(self.maplist.currentRow()) def changePreview(self): """Change the map preview.""" if self.maplist.count() < 1: return mapname = self.maplist.currentItem().text() if (mapname == "TBD"): self.pb_renameMap.setEnabled(False) self.pb_removeMap.setEnabled(False) self.sc_removeMap.setEnabled(False) else: self.pb_removeMap.setEnabled(True) self.pb_renameMap.setEnabled(True) self.sc_removeMap.setEnabled(True) file = self.controller.getMapImg(mapname, True) pixmap = QPixmap(file) height = pixmap.height() width = pixmap.width() ext = os.path.splitext(file)[1].replace(".", "").upper() size = humanize.naturalsize(os.path.getsize(file)) pixmap = QPixmap(file).scaled(self.mapsize, self.mapsize, Qt.KeepAspectRatio) self.mapPreview.setPixmap(pixmap) text = f"{width}x{height}px, {size}, {ext}" self.mapInfo.setText(text) def createButtonGroup(self): """Create buttons.""" try: layout = QHBoxLayout() layout.addWidget(QLabel("")) buttonCancel = QPushButton(_('Cancel')) buttonCancel.clicked.connect(self.closeWindow) layout.addWidget(buttonCancel) buttonSave = QPushButton(_('&Save && Close')) buttonSave.setToolTip(_("Shortcut: {}").format("Ctrl+S")) self.shortcut = QShortcut(QKeySequence("Ctrl+S"), self) self.shortcut.setAutoRepeat(False) self.shortcut.activated.connect(self.saveCloseWindow) buttonSave.clicked.connect(self.saveCloseWindow) layout.addWidget(buttonSave) self.buttonGroup = layout except Exception: module_logger.exception("message") def saveData(self): """Save the data.""" if (self.__dataChanged): scctool.settings.config.parser.set( "SCT", "myteams", ", ".join(self.list_favTeams.getData())) scctool.settings.config.parser.set( "SCT", "commonplayers", ", ".join(self.list_favPlayers.getData())) scctool.settings.config.parser.set("SCT", "tesseract", self.tesseract.text().strip()) scctool.settings.config.parser.set("SCT", "use_ocr", str(self.cb_useocr.isChecked())) scctool.settings.config.parser.set( "SCT", "new_maps_prompt", str(self.cb_newMapsPrompt.isChecked())) scctool.settings.config.parser.set( "SCT", "transparent_match_banner", str(self.cb_trans_banner.isChecked())) scctool.settings.config.parser.set( "SCT", "CtrlShiftS", str(self.cb_ctrlshifts.isChecked())) scctool.settings.config.parser.set( "SCT", "CtrlShiftC", str(self.cb_ctrlshiftc.isChecked())) scctool.settings.config.parser.set( "SCT", "swap_myteam", str(self.cb_swapTeams.isChecked())) scctool.settings.config.parser.set("SCT", "CtrlN", str(self.cb_ctrln.isChecked())) scctool.settings.config.parser.set("SCT", "CtrlX", str(self.cb_ctrlx.isChecked())) scctool.settings.config.parser.set( "SCT", "CtrlShiftR", str(self.cb_ctrlshiftr.currentText())) scctool.settings.config.parser.set( "SCT", "blacklist_on", str(self.cb_blacklist.isChecked())) scctool.settings.config.parser.set( "SCT", "blacklist", ", ".join(self.list_blacklist.getData())) scctool.settings.config.parser.set( "SCT", "sc2_network_listener_address", self.listener_address.text().strip()) scctool.settings.config.parser.set( "SCT", "sc2_network_listener_enabled", str(self.cb_usesc2listener.isChecked())) scctool.settings.config.parser.set( "Countdown", "matchgrabber_update", str(self.cb_counter_matchgrabber_update.isChecked())) scctool.settings.config.parser.set( "Countdown", "replacement", self.le_countdown_replacement.text()) scctool.settings.config.parser.set( "Countdown", "pre_txt", self.counter_pretext.toPlainText()) scctool.settings.config.parser.set( "Countdown", "post_txt", self.counter_posttext.toPlainText()) scctool.settings.config.parser.set( "Ticker", "prefix", self.ticker_pretext.text().strip()) self.controller.matchControl.tickerChanged.emit() self.controller.refreshButtonStatus() # self.controller.setCBS() self.__dataChanged = False def saveCloseWindow(self): """Save and close window.""" self.saveData() self.passEvent = True self.close() def closeWindow(self): """Close window.""" self.passEvent = True self.close() def closeEvent(self, event): """Handle close event.""" try: self.mainWindow.updateAllMapCompleters() if (not self.__dataChanged): event.accept() return if (not self.passEvent): if (self.isMinimized()): self.showNormal() buttonReply = QMessageBox.question( self, _('Save data?'), _("Save data?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.Yes: self.saveData() event.accept() except Exception: module_logger.exception("message")
class SubwindowMisc(QWidget): """Show subwindow with miscellaneous settings.""" def createWindow(self, mainWindow, tab=''): """Create subwindow with miscellaneous settings.""" try: parent = None super().__init__(parent) # self.setWindowFlags(Qt.WindowStaysOnTopHint) self.setWindowIcon( QIcon(scctool.settings.getResFile('settings.png'))) self.setWindowModality(Qt.ApplicationModal) self.mainWindow = mainWindow self.passEvent = False self.controller = mainWindow.controller self.__dataChanged = False self.createButtonGroup() self.createTabs(tab) mainLayout = QVBoxLayout() mainLayout.addWidget(self.tabs) mainLayout.addLayout(self.buttonGroup) self.setLayout(mainLayout) self.resize( QSize(mainWindow.size().width() * .80, self.sizeHint().height())) relativeChange = QPoint(mainWindow.size().width() / 2, mainWindow.size().height() / 3)\ - QPoint(self.size().width() / 2, self.size().height() / 3) self.move(mainWindow.pos() + relativeChange) self.setWindowTitle(_("Miscellaneous Settings")) except Exception as e: module_logger.exception("message") def createTabs(self, tab=''): """Create tabs.""" self.tabs = QTabWidget() self.createMapsBox() self.createFavBox() self.createAliasBox() self.createOcrBox() self.createAlphaBox() # Add tabs self.tabs.addTab(self.mapsBox, _("Map Manager")) self.tabs.addTab(self.favBox, _("Favorites")) self.tabs.addTab(self.aliasBox, _("Alias")) self.tabs.addTab(self.ocrBox, _("OCR")) self.tabs.addTab(self.alphaBox, _("AlphaTL && Ingame Score")) table = dict() table['mapmanager'] = 0 table['favorites'] = 1 table['alias'] = 2 table['ocr'] = 3 table['alphatl'] = 4 self.tabs.setCurrentIndex(table.get(tab, -1)) def changed(self): """Handle changes.""" self.__dataChanged = True def createAlphaBox(self): """Create Alpha QWidget.""" self.alphaBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("AlphaTL")) layout = QHBoxLayout() self.cb_trans_banner = QCheckBox( " " + _("Download transparent Banner of the Match")) self.cb_trans_banner.setChecked( scctool.settings.config.parser.getboolean( "SCT", "transparent_match_banner")) self.cb_trans_banner.stateChanged.connect(self.changed) layout.addWidget(self.cb_trans_banner) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Set Ingame Score Task")) layout = QVBoxLayout() self.cb_ctrlx = QCheckBox(" " + _('Automatically press Ctrl+X to apply the' ' correct player order ingame')) self.cb_ctrlx.setToolTip( _("This will ensure that the player of the first team is always" " on the left/top in the ingame Observer UI.")) self.cb_ctrlx.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlX")) self.cb_ctrlx.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrlx) self.cb_ctrln = QCheckBox(" " + _('Automatically press Ctrl+N before' ' OCR to display player names')) self.cb_ctrln.setToolTip( _("This is recommended for Standard and Gawliq Observer UI.")) self.cb_ctrln.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlN")) self.cb_ctrln.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrln) self.cb_ctrlshifts = QCheckBox( " " + _('Automatically press Ctrl+Shift+S to display' ' the ingame score')) self.cb_ctrlshifts.setToolTip( _("Ctrl+Shift+S is needed for the WCS-Gameheart Oberserver" " Overlay, but disables the sound for other overlays.")) self.cb_ctrlshifts.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlShiftS")) self.cb_ctrlshifts.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrlshifts) self.cb_ctrlshiftc = QCheckBox( " " + _('Automatically press Ctrl+Shift+C to toogle the clan tag')) self.cb_ctrlshiftc.setChecked( scctool.settings.config.parser.getboolean("SCT", "CtrlShiftC")) self.cb_ctrlshiftc.stateChanged.connect(self.changed) layout.addWidget(self.cb_ctrlshiftc) container = QHBoxLayout() self.cb_ctrlshiftr = QComboBox() self.cb_ctrlshiftr.addItem("0") self.cb_ctrlshiftr.addItem("1") self.cb_ctrlshiftr.addItem("2") try: self.cb_ctrlshiftr.setCurrentIndex( scctool.settings.config.parser.getint("SCT", "CtrlShiftR")) except Exception: self.cb_ctrlshiftr.setCurrentIndex(0) self.cb_ctrlshiftr.setMaximumWidth(40) self.cb_ctrlshiftr.currentIndexChanged.connect(self.changed) container.addWidget( QLabel( _('Automatically press Ctrl+Shift+R to toogle the race icon ')) ) container.addWidget(self.cb_ctrlshiftr) container.addWidget(QLabel(_(' time(s)'))) layout.addLayout(container) self.cb_blacklist = QCheckBox(" " + _('Activate Blacklist for' ' Ingame Score')) self.cb_blacklist.setChecked( scctool.settings.config.parser.getboolean("SCT", "blacklist_on")) self.cb_blacklist.stateChanged.connect(self.changed) layout.addWidget(self.cb_blacklist) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Blacklist for Ingame Score")) layout = QVBoxLayout() blacklistDesc = _("Enter your SC2 client usernames to deactivate" " automatically setting the ingame score and" " toogling the production tab when you are playing" " yourself. Replays are exempt.") label = QLabel(blacklistDesc) label.setAlignment(Qt.AlignJustify) label.setWordWrap(True) layout.addWidget(label) self.list_blacklist = ListTable(4, scctool.settings.config.getBlacklist()) self.list_blacklist.dataModified.connect(self.changed) self.list_blacklist.setFixedHeight(50) layout.addWidget(self.list_blacklist) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.alphaBox.setLayout(mainLayout) def createFavBox(self): """Create favorites box.""" self.favBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox(_("Players")) layout = QHBoxLayout() self.list_favPlayers = ListTable( 4, scctool.settings.config.getMyPlayers()) self.list_favPlayers.dataModified.connect(self.changed) self.list_favPlayers.setFixedHeight(150) layout.addWidget(self.list_favPlayers) box.setLayout(layout) mainLayout.addWidget(box) box = QGroupBox(_("Teams")) layout = QVBoxLayout() self.list_favTeams = ListTable(3, scctool.settings.config.getMyTeams()) self.list_favTeams.dataModified.connect(self.changed) self.list_favTeams.setFixedHeight(100) layout.addWidget(self.list_favTeams) self.cb_swapTeams = QCheckBox( _('Swap my favorite team always to the left')) self.cb_swapTeams.setChecked( scctool.settings.config.parser.getboolean("SCT", "swap_myteam")) self.cb_swapTeams.stateChanged.connect(self.changed) layout.addWidget(self.cb_swapTeams) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.favBox.setLayout(mainLayout) def createAliasBox(self): """Create favorites box.""" self.aliasBox = QWidget() mainLayout = QGridLayout() aliasDesc = _( 'Player and team aliases are replaced by the actual name when' + ' encountered by the match grabber. Additionally, SC2 player' + ' names listed as aliases are replaced in the intros' + ' and used to identify players by the automatic' + ' background tasks "Auto Score Update" and "Set Ingame Score".') label = QLabel(aliasDesc) label.setAlignment(Qt.AlignJustify) label.setWordWrap(True) mainLayout.addWidget(label, 1, 0, 1, 2) box = QGroupBox(_("Player Aliases")) layout = QVBoxLayout() self.list_aliasPlayers = AliasTreeView(self) self.list_aliasPlayers.aliasRemoved.connect( self.controller.aliasManager.removePlayerAlias) layout.addWidget(self.list_aliasPlayers) addButton = QPushButton(_("Add Alias")) addButton.clicked.connect( lambda: self.addAlias(self.list_aliasPlayers, _('Player Name'))) layout.addWidget(addButton) box.setLayout(layout) mainLayout.addWidget(box, 0, 0) box = QGroupBox(_("Team Aliases")) layout = QVBoxLayout() self.list_aliasTeams = AliasTreeView(self) self.list_aliasTeams.aliasRemoved.connect( self.controller.aliasManager.removeTeamAlias) layout.addWidget(self.list_aliasTeams) addButton = QPushButton(_("Add Alias")) addButton.clicked.connect( lambda: self.addAlias(self.list_aliasTeams, _('Team Name'))) layout.addWidget(addButton) box.setLayout(layout) mainLayout.addWidget(box, 0, 1) list = self.controller.aliasManager.playerAliasList() for player, aliases in list.items(): self.list_aliasPlayers.insertAliasList(player, aliases) list = self.controller.aliasManager.teamAliasList() for team, aliases in list.items(): self.list_aliasTeams.insertAliasList(team, aliases) self.aliasBox.setLayout(mainLayout) def addAlias(self, widget, scope, name=""): name, ok = QInputDialog.getText(self, scope, scope + ':', text=name) if not ok: return name = name.strip() alias, ok = QInputDialog.getText(self, _('Alias'), _('Alias of {}').format(name) + ':', text="") alias = alias.strip() if not ok: return try: if widget == self.list_aliasPlayers: self.controller.aliasManager.addPlayerAlias(name, alias) elif widget == self.list_aliasTeams: self.controller.aliasManager.addTeamAlias(name, alias) widget.insertAlias(name, alias, True) except Exception as e: module_logger.exception("message") QMessageBox.critical(self, _("Error"), str(e)) def createOcrBox(self): """Create forms for OCR.""" self.ocrBox = QWidget() mainLayout = QVBoxLayout() box = QGroupBox( _("Optical Character Recognition for" " Automatic Setting of Ingame Score")) layout = QGridLayout() self.cb_useocr = QCheckBox(" " + _("Activate Optical Character Recognition")) self.cb_useocr.setChecked( scctool.settings.config.parser.getboolean("SCT", "use_ocr")) self.cb_useocr.stateChanged.connect(self.changed) self.tesseract = MonitoredLineEdit() self.tesseract.setText( scctool.settings.config.parser.get("SCT", "tesseract")) self.tesseract.textModified.connect(self.changed) # self.tesseract.setAlignment(Qt.AlignCenter) self.tesseract.setPlaceholderText( "C:\\Program Files (x86)\\Tesseract-OCR\\tesseract") self.tesseract.setReadOnly(True) self.tesseract.setToolTip(_('Tesseract-OCR Executable')) self.browse = QPushButton(_("Browse...")) self.browse.clicked.connect(self.selectTesseract) text = _( "Sometimes the order of players given by the SC2-Client-API" " differs from the order in the Observer-UI resulting in a" " swapped match score. To correct this via Optical Character" " Recognition you have to download {} and install and select the" " exectuable below, if it is not detected automatically.") url = 'https://github.com/UB-Mannheim/tesseract' + \ '/wiki#tesseract-at-ub-mannheim' href = "<a href='{}'>" + "Tesseract-OCR" + "</a>" href = href.format(url) label = QLabel(text.format(href)) label.setAlignment(Qt.AlignJustify) label.setOpenExternalLinks(True) label.setWordWrap(True) label.setMargin(5) layout.addWidget(label, 1, 0, 1, 2) layout.addWidget(self.cb_useocr, 0, 0, 1, 2) layout.addWidget(QLabel(_("Tesseract-OCR Executable") + ":"), 2, 0) layout.addWidget(self.tesseract, 3, 0) layout.addWidget(self.browse, 3, 1) box.setLayout(layout) mainLayout.addWidget(box) mainLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.ocrBox.setLayout(mainLayout) if (not scctool.settings.windows): self.cb_useocr.setEnabled(False) self.cb_useocr.setAttribute(Qt.WA_AlwaysShowToolTips) self.cb_useocr.setToolTip( _("This feature is only available in Windows.")) self.tesseract.setEnabled(False) self.tesseract.setAttribute(Qt.WA_AlwaysShowToolTips) self.tesseract.setToolTip( _("This feature is only available in Windows.")) self.browse.setEnabled(False) self.browse.setAttribute(Qt.WA_AlwaysShowToolTips) self.browse.setToolTip( _("This feature is only available in Windows.")) def selectTesseract(self): """Create forms for tesseract.""" old_exe = self.tesseract.text() default = scctool.settings.config.findTesserAct(old_exe) exe, ok = QFileDialog.getOpenFileName( self, _("Select Tesseract-OCR Executable"), default, _("Tesseract-OCR Executable") + " (tesseract.exe);; " + _("Executable") + " (*.exe);; " + _("All files") + " (*)") if (ok and exe != old_exe): self.tesseract.setText(exe) self.changed() def createMapsBox(self): """Create box for map manager.""" self.mapsize = 300 self.mapsBox = QWidget() layout = QGridLayout() self.maplist = QListWidget() self.maplist.setSortingEnabled(True) for map in scctool.settings.maps: self.maplist.addItem(QListWidgetItem(map)) self.maplist.setCurrentItem(self.maplist.item(0)) self.maplist.currentItemChanged.connect(self.changePreview) # self.maplist.setFixedHeight(self.mapsize) self.maplist.setMinimumWidth(150) layout.addWidget(self.maplist, 0, 1, 2, 1) self.mapPreview = QLabel() self.mapPreview.setFixedWidth(self.mapsize) self.mapPreview.setFixedHeight(self.mapsize) self.mapPreview.setAlignment(Qt.AlignCenter) layout.addWidget(self.mapPreview, 0, 0) self.mapInfo = QLabel() self.mapInfo.setIndent(10) layout.addWidget(self.mapInfo, 1, 0) self.pb_addMapLiquipedia = QPushButton(_("Add from Liquipedia")) self.pb_addMapLiquipedia.clicked.connect(self.addFromLquipedia) self.pb_addMap = QPushButton(_("Add from File")) self.pb_addMap.clicked.connect(self.addMap) self.pb_renameMap = QPushButton(_("Rename")) self.pb_renameMap.clicked.connect(self.renameMap) self.pb_changeMap = QPushButton(_("Change Image")) self.pb_changeMap.clicked.connect(self.changeMap) self.pb_removeMap = QPushButton(_("Remove")) self.pb_removeMap.clicked.connect(self.deleteMap) self.sc_removeMap = QShortcut(QKeySequence("Del"), self) self.sc_removeMap.setAutoRepeat(False) self.sc_removeMap.activated.connect(self.deleteMap) box = QWidget() container = QHBoxLayout() container.addWidget(self.pb_addMapLiquipedia, 0) container.addWidget(self.pb_addMap, 0) container.addWidget(QLabel(), 4) container.addWidget(self.pb_renameMap, 0) container.addWidget(self.pb_changeMap, 0) container.addWidget(self.pb_removeMap, 0) box.setLayout(container) layout.addWidget(box, 2, 0, 1, 2) layout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), 3, 0, 1, 2) self.changePreview() self.mapsBox.setLayout(layout) def renameMap(self): """Rename maps.""" item = self.maplist.currentItem() map = item.text() text, ok = QInputDialog.getText(self, _('Map Name'), _('Map Name') + ':', text=map) if not ok: return text = text.strip() if (text == map): return if text.lower() == 'tbd': QMessageBox.critical( self, _("Error"), _('"{}" is not a valid map name.').format(text)) return if (text in scctool.settings.maps): buttonReply = QMessageBox.warning( self, _("Duplicate Entry"), _("Map is already in list! Overwrite?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.No: return self.controller.addMap(self.controller.getMapImg(map, True), text) self.controller.deleteMap(map) item.setText(text) def changeMap(self): """Change a map.""" map = self.maplist.currentItem().text() fileName, ok = QFileDialog.getOpenFileName( self, _("Select Map Image (> 500x500px recommended)"), "", _("Supported Images") + " (*.png *.jpg)") if ok: base = os.path.basename(fileName) name, ext = os.path.splitext(base) name = name.replace("_", " ") self.controller.deleteMap(map) self.controller.addMap(fileName, map) self.changePreview() def addMap(self): """Add a map.""" fileName, ok = QFileDialog.getOpenFileName( self, _("Select Map Image (> 500x500px recommended)"), "", _("Supported Images") + " (*.png *.jpg)") if ok: base = os.path.basename(fileName) name, ext = os.path.splitext(base) name = name.replace("_", " ") map_name, ok = QInputDialog.getText(self, _('Map Name'), _('Map Name') + ':', text=name) map_name = map_name.strip() if ok: if map_name.lower() == 'tbd': QMessageBox.critical( self, _("Error"), _('"{}" is not a valid map name.').format(map_name)) return if (map_name in scctool.settings.maps): buttonReply = QMessageBox.warning( self, _("Duplicate Entry"), _("Map is already in list! Overwrite?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.No: return else: self.controller.deleteMap(map_name) self.controller.addMap(fileName, map_name) items = self.maplist.findItems(map_name, Qt.MatchExactly) if len(items) == 0: item = QListWidgetItem(map_name) self.maplist.addItem(item) self.maplist.setCurrentItem(item) else: self.maplist.setCurrentItem(items[0]) self.changePreview() def addFromLquipedia(self): grabber = LiquipediaGrabber() search_str = '' while True: search_str, ok = QInputDialog.getText(self, _('Map Name'), _('Map Name') + ':', text=search_str) search_str.strip() try: if ok and search_str: if search_str.lower() == 'tbd': QMessageBox.critical( self, _("Error"), _('"{}" is not a valid map name.').format( search_str)) continue try: map = grabber.get_map(search_str) except MapNotFound: QMessageBox.critical( self, _("Map not found"), _('"{}" was not found on Liquipedia.').format( search_str)) continue map_name = map.get_name() if (map_name in scctool.settings.maps): buttonReply = QMessageBox.warning( self, _("Duplicate Entry"), _("Map {} is already in list! Overwrite?".format( map_name)), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.No: break else: self.controller.deleteMap(map_name) images = grabber.get_images(map.get_map_images()) image = "" for size in sorted(images): if not image or size <= 2500 * 2500: image = images[size] url = grabber._base_url + image downloader = MapDownloader(self, map_name, url) downloader.download() if map_name not in scctool.settings.maps: scctool.settings.maps.append(map_name) items = self.maplist.findItems(map_name, Qt.MatchExactly) if len(items) == 0: item = QListWidgetItem(map_name) self.maplist.addItem(item) self.maplist.setCurrentItem(item) else: self.maplist.setCurrentItem(items[0]) self.changePreview() except Exception as e: module_logger.exception("message") QMessageBox.critical(self, _("Error"), str(e)) finally: break def deleteMap(self): """Delete a map.""" item = self.maplist.currentItem() map = item.text() buttonReply = QMessageBox.question( self, _('Delete map?'), _("Delete '{}' permanently?").format(map), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.Yes: self.controller.deleteMap(map) self.maplist.takeItem(self.maplist.currentRow()) def changePreview(self): """Change the map preview.""" if self.maplist.count() < 1: return map = self.maplist.currentItem().text() if (map == "TBD"): self.pb_renameMap.setEnabled(False) self.pb_removeMap.setEnabled(False) self.sc_removeMap.setEnabled(False) else: self.pb_removeMap.setEnabled(True) self.pb_renameMap.setEnabled(True) self.sc_removeMap.setEnabled(True) file = self.controller.getMapImg(map, True) map = QPixmap(file) width = map.height() height = map.width() ext = os.path.splitext(file)[1].replace(".", "").upper() size = humanize.naturalsize(os.path.getsize(file)) map = QPixmap(file).scaled(self.mapsize, self.mapsize, Qt.KeepAspectRatio) self.mapPreview.setPixmap(map) text = "{}x{}px, {}, {}".format(width, height, str(size), ext) self.mapInfo.setText(text) def createButtonGroup(self): """Create buttons.""" try: layout = QHBoxLayout() layout.addWidget(QLabel("")) buttonCancel = QPushButton(_('Cancel')) buttonCancel.clicked.connect(self.closeWindow) layout.addWidget(buttonCancel) buttonSave = QPushButton(_('&Save && Close')) buttonSave.setToolTip(_("Shortcut: {}").format("Ctrl+S")) self.shortcut = QShortcut(QKeySequence("Ctrl+S"), self) self.shortcut.setAutoRepeat(False) self.shortcut.activated.connect(self.saveCloseWindow) buttonSave.clicked.connect(self.saveCloseWindow) layout.addWidget(buttonSave) self.buttonGroup = layout except Exception as e: module_logger.exception("message") def saveData(self): """Save the data.""" if (self.__dataChanged): scctool.settings.config.parser.set( "SCT", "myteams", ", ".join(self.list_favTeams.getData())) scctool.settings.config.parser.set( "SCT", "commonplayers", ", ".join(self.list_favPlayers.getData())) scctool.settings.config.parser.set("SCT", "tesseract", self.tesseract.text().strip()) scctool.settings.config.parser.set("SCT", "use_ocr", str(self.cb_useocr.isChecked())) scctool.settings.config.parser.set( "SCT", "transparent_match_banner", str(self.cb_trans_banner.isChecked())) scctool.settings.config.parser.set( "SCT", "CtrlShiftS", str(self.cb_ctrlshifts.isChecked())) scctool.settings.config.parser.set( "SCT", "CtrlShiftC", str(self.cb_ctrlshiftc.isChecked())) scctool.settings.config.parser.set( "SCT", "swap_myteam", str(self.cb_swapTeams.isChecked())) scctool.settings.config.parser.set("SCT", "CtrlN", str(self.cb_ctrln.isChecked())) scctool.settings.config.parser.set("SCT", "CtrlX", str(self.cb_ctrlx.isChecked())) scctool.settings.config.parser.set( "SCT", "CtrlShiftR", str(self.cb_ctrlshiftr.currentText())) scctool.settings.config.parser.set( "SCT", "blacklist_on", str(self.cb_blacklist.isChecked())) scctool.settings.config.parser.set( "SCT", "blacklist", ", ".join(self.list_blacklist.getData())) self.__dataChanged = False def saveCloseWindow(self): """Save and close window.""" self.saveData() self.passEvent = True self.close() def closeWindow(self): """Close window.""" self.passEvent = True self.close() def closeEvent(self, event): """Handle close event.""" try: self.mainWindow.updateMapCompleters() if (not self.__dataChanged): event.accept() return if (not self.passEvent): if (self.isMinimized()): self.showNormal() buttonReply = QMessageBox.question( self, _('Save data?'), _("Save data?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.Yes: self.saveData() event.accept() except Exception as e: module_logger.exception("message")