Example #1
0
class SideBar(QWidget):
    def __init__(self, manager, window):
        super().__init__(window)
        self._window = window  # BrowserWindow
        self._layout = None  # QVBoxLayout
        self._titleBar = None  # DockTitleBarWidget
        self._manager = manager  # SideBarManager

        self.setObjectName('sidebar')
        self.setAttribute(Qt.WA_DeleteOnClose)

        self._layout = QVBoxLayout(self)
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)
        self.setLayout(self._layout)

        self._titleBar = DockTitleBarWidget('', self)
        self._layout.addWidget(self._titleBar)

    def showBookmarks(self):
        self._titleBar.setTitle(_('Bookmarks'))
        bar = BookmarksSideBar(self._window)
        self.setWidget(bar)

    def showHistory(self):
        self._titleBar.setTitle(_('History'))
        bar = HistorySideBar(self._window)
        self.setWidget(bar)

    def setTitle(self, title):
        self._titleBar.setTitle(title)

    def setWidget(self, widget):
        if self._layout.count() == 2:
            self._layout.removeItem(self._layout.itemAt(1))

        if widget:
            self._layout.addWidget(widget)

    # Q_SLOTS
    def close(self):
        self._manager.closeSideBar()

        p = self.parentWidget()
        if p:
            p.setFocus()

        super().close()
Example #2
0
class PlayWidget(QWidget):
    def __init__(self, parent):
        super(PlayWidget, self).__init__(parent)
        self.setAutoFillBackground(True)
        self.hlayout = QHBoxLayout(self)

        self.table_view = CardView(self)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.table_view.sizePolicy().hasHeightForWidth())
        self.table_view.setSizePolicy(sizePolicy)
        self.table_view.setMinimumHeight(200)
        self.table_view.setBackgroundBrush(Qt.darkGreen)
        self.table_view.setGeometry(0, 0, 1028, 200)

        self.hand_view = HandCardView(self)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.hand_view.sizePolicy().hasHeightForWidth())
        self.hand_view.setSizePolicy(sizePolicy)
        self.hand_view.setMinimumHeight(200)
        self.hand_view.setBackgroundBrush(Qt.darkGreen)
        self.hand_view.setGeometry(0, 0, 1028, 200)

        self.show_button = Button(self, 'Show Hand')
        self.show_button.setText("Show hand")
        self.show_button.clicked.connect(self.hand_view.show_cards)
        self.show_button.hide()

        self.move_button = Button(self, 'Make Move')
        self.move_button.setMinimumSize(300, 100)
        self.move_button.clicked.connect(self.attempt_move)
        self.move_button.hide()

        self.start_button = Button(self, 'Start Round')
        self.start_button.setMinimumHeight(100)
        self.start_button.clicked.connect(self.start_round)

        self.next_button = Button(self, 'Continue')
        self.next_button.setMinimumHeight(100)
        self.next_button.clicked.connect(self.goto_next_round)
        self.next_button.hide()

        self.quit_button = Button(self, 'Quit to menu')

        self.save_button = Button(self, 'Save')

        self.show_button.setMaximumWidth(150)
        self.move_button.setMaximumWidth(150)
        self.quit_button.setMaximumWidth(150)

        self.btnlayout = QHBoxLayout()
        self.btnlayout.addWidget(self.start_button)

        self.btn2layout = QHBoxLayout()
        self.btn2layout.addWidget(self.save_button)
        self.btn2layout.addWidget(self.quit_button)

        self.playlayout = QVBoxLayout()
        self.playlayout.addWidget(self.table_view)
        self.playlayout.addLayout(self.btnlayout)
        self.playlayout.addWidget(self.hand_view)
        self.playlayout.addLayout(self.btn2layout)
        self.hlayout.addLayout(self.playlayout)

        self.sidelayout = QVBoxLayout()
        self.log = QPlainTextEdit()
        self.log.setReadOnly(True)
        self.log.setPalette(QPalette(Qt.white))
        self.log.setMaximumWidth(300)
        self.log.setMaximumHeight(200)
        self.sidelayout.addWidget(self.log)

        self.playerinfolayout = QVBoxLayout()
        self.sidelayout.addLayout(self.playerinfolayout)

        self.sidelayout.addItem(
            QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))

        self.hlayout.addLayout(self.sidelayout)

        self.setup_sound()

        self.move_count = 0
        self.speed = 3
        self.game = None

    def init_game(self, game):
        self.game = game
        self.game.logSignal.connect(self.update_log)
        self.game.sweepSignal.connect(self.sweep_sound.play)

        self.game.new_round()
        self.shuffle_sound.play()
        self.game.initial_deal()

        self.move_count = 0

        for player in self.game.players:
            self.playerinfolayout.addWidget(PlayerInfo(self, player))

    def start_round(self):
        self.btnlayout.removeWidget(self.start_button)
        self.btnlayout.insertWidget(0, self.show_button)
        self.btnlayout.insertWidget(1, self.move_button)
        self.start_button.hide()
        self.show_button.show()
        self.move_button.show()

        self.table_view.update_scene(self.game.table)
        self.hand_view.update_scene(self.game.current_player.hand)

        self.hand_view.hide_cards()

        if type(self.game.current_player
                ) is not AIPlayer and self.game.one_human:
            self.hand_view.show_cards()

        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().set_active()
        self.update_log('\n----------\n{}\'s turn\n'.format(
            self.game.current_player))

        if type(self.game.current_player) is AIPlayer:
            self.move_button.setDisabled(True)
            self.show_button.setDisabled(True)
            self.save_button.setDisabled(True)
            self.make_ai_move()

    def resume_from_save(self, game, logmsg, movecount):
        self.game = game
        self.game.logSignal.connect(self.update_log)
        self.game.sweepSignal.connect(self.sweep_sound.play)

        self.log.insertPlainText(logmsg)
        self.log.insertPlainText(
            '\n----------------\n    Resuming from save\n----------------\n\n')

        self.move_count = movecount

        for player in self.game.players:
            self.playerinfolayout.addWidget(PlayerInfo(self, player))

        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().set_active()

    def make_ai_move(self):
        self.game.select_move_for_ai()
        QTimer.singleShot(1500 // self.speed, self.show_ai_move)

    def show_ai_move(self):
        self.hand_view.auto_select()
        self.table_view.auto_select()
        self.card_sound.play()
        self.game.do_action()
        QTimer.singleShot(3000 // self.speed, self.after_ai_move_done)

    def after_ai_move_done(self):
        self.move_sound.play()
        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().update_info()
        self.game.deal()
        self.table_view.update_scene(self.game.table)
        self.hand_view.update_scene(self.game.current_player.hand)
        self.hand_view.hide_cards()
        QTimer.singleShot(3000 // self.speed, self.end_turn)

    def attempt_move(self):
        if self.game.do_action():
            self.move_sound.play()
            self.playerinfolayout.itemAt(
                self.game.players.index(
                    self.game.current_player)).widget().update_info()
            self.move_button.setDisabled(True)
            self.table_view.update_scene(self.game.table)
            self.hand_view.update_scene(self.game.current_player.hand)
            QTimer.singleShot(1800 // self.speed, self.after_move_done)

        else:
            self.error_sound.play()

    def after_move_done(self):
        self.game.deal()
        self.hand_view.update_scene(self.game.current_player.hand)
        QTimer.singleShot(3000 // self.speed, self.end_turn)

    def end_turn(self):
        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().set_inactive()
        self.game.next_player()
        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().set_active()

        self.move_button.setDisabled(False)
        self.show_button.setDisabled(False)
        self.table_view.deselect_all()

        self.move_count += 1
        if self.move_count == 48:
            self.end_round()
            return

        self.update_log('\n----------\n{}\'s turn\n'.format(
            self.game.current_player))
        self.hand_view.update_scene(self.game.current_player.hand)
        self.hand_view.hide_cards()

        #if there is only one human player, his/her cards are shown automatically
        if type(self.game.current_player
                ) is not AIPlayer and self.game.one_human:
            self.hand_view.show_cards()
            self.alert_sound.play()

        if type(self.game.current_player) is AIPlayer:
            self.move_button.setDisabled(True)
            self.show_button.setDisabled(True)
            self.save_button.setDisabled(True)
            self.make_ai_move()
            return

        self.save_button.setDisabled(False)

    def end_round(self):
        self.save_button.setDisabled(True)
        self.playerinfolayout.itemAt(
            self.game.players.index(
                self.game.current_player)).widget().set_inactive()
        self.end_sound.play()
        game_ended = self.game.end_round()
        for i in range(self.playerinfolayout.count()):
            self.playerinfolayout.itemAt(i).widget().update_info()
            self.playerinfolayout.itemAt(i).widget().update_score()

        self.table_view.update_scene(self.game.table)

        self.btnlayout.removeWidget(self.show_button)
        self.btnlayout.removeWidget(self.move_button)
        self.btnlayout.insertWidget(0, self.next_button)
        self.next_button.show()
        self.show_button.hide()
        self.move_button.hide()
        if game_ended:
            self.next_button.setDisabled(True)

    def goto_next_round(self):
        self.save_button.setDisabled(False)
        self.btnlayout.removeWidget(self.next_button)
        self.btnlayout.insertWidget(0, self.start_button)
        self.start_button.show()
        self.next_button.hide()

        #rotate playerinfo
        mov = self.playerinfolayout.itemAt(0).widget()
        self.playerinfolayout.removeWidget(mov)
        self.playerinfolayout.addWidget(mov)

        self.game.new_round()
        self.shuffle_sound.play()

        for i in range(self.playerinfolayout.count()):
            self.playerinfolayout.itemAt(i).widget().update_info()

        self.game.new_round()
        self.game.initial_deal()

        self.move_count = 0

    def setup_sound(self):
        self.shuffle_sound = QSoundEffect()
        self.shuffle_sound.setSource(QUrl.fromLocalFile('sound/shuffle.wav'))

        self.error_sound = QSoundEffect()
        self.error_sound.setSource(QUrl.fromLocalFile('sound/error.wav'))

        self.move_sound = QSoundEffect()
        self.move_sound.setSource(QUrl.fromLocalFile('sound/draw.wav'))

        self.card_sound = QSoundEffect()
        self.card_sound.setSource(QUrl.fromLocalFile('sound/playcard.wav'))

        self.sweep_sound = QSoundEffect()
        self.sweep_sound.setSource(QUrl.fromLocalFile('sound/sweep.wav'))

        self.alert_sound = QSoundEffect()
        self.alert_sound.setSource(QUrl.fromLocalFile('sound/alert.wav'))

        self.end_sound = QSoundEffect()
        self.end_sound.setSource(QUrl.fromLocalFile('sound/endturn.wav'))

    def reset(self):
        self.game = None

    def update_log(self, msg):
        self.log.insertPlainText(msg)
        self.log.ensureCursorVisible()  #auto-scrolls to bottom of log

    def export_log(self):
        return self.log.toPlainText()
Example #3
0
class StartMenu(QWidget):
    
    def __init__(self, parent):
        super(StartMenu, self).__init__(parent)
        
        self.tophbox = QHBoxLayout()
        self.hbox = QHBoxLayout()
        self.vbox = QVBoxLayout()
        
        self.label = QLabel()
        self.label.setPixmap(QPixmap('img/new-game.png'))
        self.label.setScaledContents(True)
        self.label.setFixedSize(600, 200)
        self.tophbox.addWidget(self.label)
        
        self.startbutton = Button(self, 'Start')
        self.startbutton.setEnabled(False)
        self.startbutton.setFixedHeight(100)
        self.tophbox.addWidget(self.startbutton)
        
        self.playeramt_label = QLabel('Number of players:')
        self.playeramt_label.setFixedWidth(125)
        
        self.playeramount = QComboBox()
        self.playeramount.setStyleSheet('color: rgb(0, 0, 0)')
        self.playeramount.setFixedWidth(50)
        self.playeramount.addItems([str(i) for i in range(2, 13)])
        self.playeramount.setCurrentIndex(2)
        self.playeramount.setMaxVisibleItems(11)
        self.playeramount.currentTextChanged.connect(self.form_player_entries)
        
        self.score_label = QLabel('Score limit:')
        self.score_label.setFixedWidth(65)
        
        self.score_limit = QLineEdit()
        self.score_limit.setMaximumWidth(40)
        self.score_limit.setPalette(QPalette(Qt.white))
        self.score_limit.setText('16')
        
        self.mode_label = QLabel('Game Mode:')
        self.mode_label.setFixedWidth(85)
        
        self.mode_select = QComboBox()
        self.mode_select.addItems(['Deal-1', 'Deal-4'])
        self.mode_select.setPalette(QPalette(Qt.white))
        self.mode_select.setFixedWidth(100)
        self.mode_select.currentTextChanged.connect(self.update_playeramount)
            
        self.autofill_button = Button(self, 'Auto Fill')
        self.autofill_button.clicked.connect(self.auto_fill)
        self.clear_button = Button(self, 'Clear All')
        self.clear_button.clicked.connect(self.clear_all)
        
        self.player_entries = QVBoxLayout()
        
        self.spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        
        self.hbox.addWidget(self.playeramt_label)
        self.hbox.addWidget(self.playeramount)
        self.hbox.addWidget(self.score_label)
        self.hbox.addWidget(self.score_limit)
        self.hbox.addWidget(self.mode_label)
        self.hbox.addWidget(self.mode_select)
        self.hbox.addWidget(self.autofill_button)
        self.hbox.addWidget(self.clear_button)
        
        self.vbox.addLayout(self.tophbox)
        self.vbox.addLayout(self.hbox)
        self.vbox.addLayout(self.player_entries)
        self.vbox.addItem(self.spacer)
        
        self.setLayout(self.vbox)
        
        self.form_player_entries() 


    def form_player_entries(self):
        amt = self.playeramount.currentIndex() + 2  #desired amount of player entries
        curr = self.player_entries.count()          #current amount of player entries
        dif = amt - self.player_entries.count()     #difference between desired and current entries
        
        if dif < 0:                                 #if too many entries currently 
            for i in range(curr-1, amt-1, -1):      #remove starting from last entry
                rm = self.player_entries.itemAt(i).widget()
                self.player_entries.removeWidget(rm)
                rm.setParent(None)
                
        
        else:                                       #if too few entries, add until desired amount reached
            for i in range(dif):
                new_entry = PlayerInfoField(self, self.player_entries.count())
                new_entry.name_field.textChanged.connect(self.check_filled)
                self.player_entries.addWidget(new_entry)
         
        self.check_filled()       
    
    
    def check_filled(self): #Enables start button when player fields are correctly filled
        ready = True
        
        for i in range(self.player_entries.count()):
            entry = self.player_entries.itemAt(i).widget()
            if entry.name_field.text() == '':
                ready = False
                break
            
        if ready:
            self.startbutton.setEnabled(True)
        else:
            self.startbutton.setEnabled(False)
            
                
    def auto_fill(self): #Generates fills the rest of the form automatically
        for i in range(self.player_entries.count()):
            entry = self.player_entries.itemAt(i).widget()
            if entry.name_field.text() == '':
                entry.generate_name()
                entry.AItoggle.setChecked(True)
                
    def clear_all(self):
        for i in range(self.player_entries.count()):
            entry = self.player_entries.itemAt(i).widget()
            entry.name_field.clear()
            entry.AItoggle.setChecked(False)
            
    def update_playeramount(self, mode):
        ind = self.playeramount.currentIndex()
        if mode == 'Deal-1': #Limit max players to 12
            self.playeramount.clear()
            self.playeramount.addItems([str(i) for i in range(2, 13)])
            self.playeramount.setCurrentIndex(ind)
            
        if mode == 'Deal-4': #Limit max players to 4
            self.playeramount.clear()
            self.playeramount.addItems([str(i) for i in range(2, 5)])
            self.playeramount.setCurrentIndex(min(2, ind))
            
        self.check_filled()
            
                
    def extract_info_and_init_game(self): #Creates a game object based on the info 
        pointlimit = int(self.score_limit.text())
        dealmode = self.mode_select.currentIndex()
        game = Game(pointlimit, dealmode)
        
        for i in range(self.player_entries.count()):
            entry = self.player_entries.itemAt(i).widget()
            name = entry.name_field.text()
            if entry.AItoggle.isChecked():
                difficulty = entry.AIdifficulty.currentIndex()
                game.add_player(name, difficulty)
            else:
                game.add_player(name, 5)
            
        return game
Example #4
0
class _ExecuteTab(QTabWidget):
    """Tab used to execute modules or shell commands on the selected bot."""
    def __init__(self, responses_tab: _ResponsesTab, model):
        super().__init__()

        self._model = model
        self._current_layout = None
        self._current_bot = None

        self._layout = QGridLayout()
        self._sub_layout = QVBoxLayout()
        self._module_view = ModuleView(responses_tab)

        self._layout.setAlignment(Qt.AlignTop)
        self.setLayout(self._layout)
        self.set_empty_layout()

    def set_current_bot(self, bot: Bot):
        """Sets the connected bot this tab will interact with."""
        self._current_bot = bot

    def _clear_layout(self):
        while self._layout.count():
            child = self._layout.takeAt(0)

            if child.widget():
                child.widget().deleteLater()
        while self._sub_layout.count():
            child = self._sub_layout.takeAt(0)

            if child.widget():
                child.widget().deleteLater()

    def set_empty_layout(self):
        """Default layout shown when the user has not yet selected a row."""
        self._current_layout = "Empty"
        self._clear_layout()

        self._layout.addWidget(
            QLabel("Please select a bot in the table above."), 0, 0)

    def set_module_layout(self, module_name: str = "screenshot"):
        """Sets the layout which can execute modules."""
        self._current_layout = "Module"
        self._clear_layout()

        command_type_label = QLabel("Command type: ")
        command_type_combobox = QComboBox()

        command_type_combobox.addItem("Module")
        command_type_combobox.addItem("Shell")

        module_label = QLabel("Module name: ")
        module_combobox = QComboBox()

        for module_name in modules.get_names():
            module_combobox.addItem(module_name)

        module_combobox.currentTextChanged.connect(self._on_module_change)
        command_type_combobox.currentTextChanged.connect(
            self._on_command_type_change)

        self._layout.setColumnStretch(1, 1)
        self._layout.addWidget(command_type_label, 0, 0)
        self._layout.addWidget(command_type_combobox, 0, 1)
        self._layout.addWidget(module_label, 1, 0)
        self._layout.addWidget(module_combobox, 1, 1)

        # Module layout
        cached_module = modules.get_module(module_name)

        if not cached_module:
            cached_module = modules.load_module(module_name, self._module_view,
                                                self._model)

        input_fields = []

        for option_name in cached_module.get_setup_messages():
            input_field = QLineEdit()

            self._sub_layout.addWidget(QLabel(option_name))
            self._sub_layout.addWidget(input_field)
            input_fields.append(input_field)

        run_button = QPushButton("Run")
        run_button.setMaximumWidth(250)
        run_button.setMinimumHeight(25)

        run_button.pressed.connect(lambda: self._on_module_run(
            module_combobox.currentText(), input_fields))

        self._sub_layout.addWidget(QLabel(""))
        self._sub_layout.addWidget(run_button)
        self._sub_layout.setContentsMargins(0, 15, 0, 0)
        self._layout.addLayout(self._sub_layout,
                               self._layout.rowCount() + 2, 0, 1, 2)

        self._on_module_change(module_combobox.currentText())

    def set_shell_layout(self):
        """Sets the layout which can execute shell commands."""
        self._current_layout = "Shell"
        self._clear_layout()

        command_type_label = QLabel("Command type: ")
        command_type_combobox = QComboBox()

        command_type_combobox.addItem("Shell")
        command_type_combobox.addItem("Module")

        command_label = QLabel("Command:")
        command_input = QLineEdit()

        run_button = QPushButton("Run")
        run_button.setMaximumWidth(250)
        run_button.setMinimumHeight(25)

        command_type_combobox.currentTextChanged.connect(
            self._on_command_type_change)
        run_button.pressed.connect(lambda: self._on_command_run(command_input))

        self._layout.addWidget(command_type_label, 0, 0)
        self._layout.addWidget(command_type_combobox, 0, 1)
        self._layout.addWidget(command_label, 1, 0)
        self._layout.addWidget(command_input, 1, 1)

        self._sub_layout.addWidget(QLabel(""))
        self._sub_layout.addWidget(run_button)
        self._sub_layout.setContentsMargins(0, 15, 0, 0)
        self._layout.addLayout(self._sub_layout,
                               self._layout.rowCount() + 2, 0, 1, 2)

    def _on_command_type_change(self, text: str):
        """Handles the command type combobox change event."""
        if text == "Module":
            self.set_module_layout()
        else:
            self.set_shell_layout()

    def _on_module_change(self, module_name: str):
        """Handles module combobox changes."""
        while self._sub_layout.count():
            child = self._sub_layout.takeAt(0)

            if child.widget():
                child.widget().deleteLater()

        cached_module = modules.get_module(module_name)

        if not cached_module:
            cached_module = modules.load_module(module_name, self._module_view,
                                                self._model)

        input_fields = []

        for option_name in cached_module.get_setup_messages():
            input_field = QLineEdit()
            input_fields.append(input_field)

            self._sub_layout.addWidget(QLabel(option_name))
            self._sub_layout.addWidget(input_field)

        run_button = QPushButton("Run")
        run_button.setMaximumWidth(250)
        run_button.setMinimumHeight(25)

        run_button.pressed.connect(
            lambda: self._on_module_run(module_name, input_fields))

        self._sub_layout.addWidget(QLabel(""))
        self._sub_layout.addWidget(run_button)
        self._sub_layout.setContentsMargins(0, 15, 0, 0)

    def display_info(self, text: str):
        message_box = QMessageBox()

        message_box.setIcon(QMessageBox.Information)
        message_box.setWindowTitle("Information")
        message_box.setText(text)
        message_box.setStandardButtons(QMessageBox.Ok)
        message_box.exec_()

    def _on_module_run(self, module_name: str, input_fields: list):
        """Handles running modules."""
        set_options = []

        for input_field in input_fields:
            set_options.append(input_field.text())

        module = modules.get_module(module_name)

        if not module:
            module = modules.load_module(module_name, self._module_view,
                                         self._model)

        successful, options = module.setup(set_options)

        if successful:
            if module_name == "remove_bot":
                code = loaders.get_remove_code(self._current_bot.loader_name)
            elif module_name == "update_bot":
                code = loaders.get_update_code(self._current_bot.loader_name)
            else:
                code = modules.get_code(module_name)

            if not options:
                options = {}

            options["module_name"] = module_name

            self._model.add_command(self._current_bot.uid,
                                    Command(CommandType.MODULE, code, options))

            self.display_info("Module added to the queue of:\n {}@{}".format(
                self._current_bot.username, self._current_bot.hostname))

    def _on_command_run(self, command_input: QLineEdit):
        """Handles running commands."""
        if command_input.text().strip() == "":
            return

        self._model.add_command(
            self._current_bot.uid,
            Command(CommandType.SHELL,
                    command_input.text().encode()))

        command_input.clear()
        self.display_info("Command added to the queue of:\n {}@{}".format(
            self._current_bot.username, self._current_bot.hostname))
Example #5
0
class _BuilderTab(QWidget):
    """Handles the creation of launchers."""
    def __init__(self):
        super().__init__()

        self._layout = QVBoxLayout()

        host_label = QLabel("Server host (where EvilOSX will connect to):")
        self._host_field = QLineEdit()

        self._layout.addWidget(host_label)
        self._layout.addWidget(self._host_field)

        port_label = QLabel("Server port:")
        self._port_field = QLineEdit()

        self._layout.addWidget(port_label)
        self._layout.addWidget(self._port_field)

        live_label = QLabel(
            "Where should EvilOSX live? (Leave empty for ~/Library/Containers/.<RANDOM>): "
        )
        self._live_field = QLineEdit()

        self._layout.addWidget(live_label)
        self._layout.addWidget(self._live_field)

        launcher_label = QLabel("Launcher name:")
        self._launcher_combobox = QComboBox()

        for launcher_name in launchers.get_names():
            self._launcher_combobox.addItem(launcher_name)

        self._layout.addWidget(launcher_label)
        self._layout.addWidget(self._launcher_combobox)

        loader_label = QLabel("Loader name:")
        loader_combobox = QComboBox()
        self._loader_layout = QVBoxLayout()

        for loader_name in loaders.get_names():
            loader_combobox.addItem(loader_name)

        self._layout.addWidget(loader_label)
        self._layout.addWidget(loader_combobox)
        loader_combobox.currentTextChanged.connect(self._set_on_loader_change)

        # Dynamically loaded loader layout
        self._layout.addLayout(self._loader_layout)
        self._set_on_loader_change(loader_combobox.currentText())

        self._layout.setContentsMargins(10, 10, 10, 0)
        self._layout.setAlignment(Qt.AlignTop)
        self.setLayout(self._layout)

    def _set_on_loader_change(self, new_text: str):
        """Handles the loader combobox change event."""
        while self._loader_layout.count():
            child = self._loader_layout.takeAt(0)

            if child.widget():
                child.widget().deleteLater()

        input_fields = []

        for message in loaders.get_option_messages(new_text):
            input_field = QLineEdit()

            self._loader_layout.addWidget(QLabel(message))
            self._loader_layout.addWidget(input_field)
            input_fields.append(input_field)

        create_button = QPushButton("Create launcher")
        create_button.setMaximumWidth(250)
        create_button.setMinimumHeight(30)
        create_button.pressed.connect(lambda: self._on_create_launcher(
            self._host_field.text(), self._port_field.text(),
            self._live_field.text(), new_text,
            self._launcher_combobox.currentText(), input_fields))

        self._loader_layout.addWidget(QLabel(""))
        self._loader_layout.addWidget(create_button)

    @staticmethod
    def display_error(text: str):
        """Displays an error message to the user."""
        message = QMessageBox()

        message.setIcon(QMessageBox.Critical)
        message.setWindowTitle("Error")
        message.setText(text)
        message.setStandardButtons(QMessageBox.Ok)
        message.exec_()

    @staticmethod
    def display_info(text: str):
        message = QMessageBox()

        message.setIcon(QMessageBox.Information)
        message.setWindowTitle("Information")
        message.setText(text)
        message.setStandardButtons(QMessageBox.Ok)
        message.exec_()

    def _on_create_launcher(self, server_host, server_port, program_directory,
                            loader_name: str, launcher_name: str,
                            input_fields: list):
        """Creates the launcher and outputs it to the builds directory."""
        if not self._host_field.text():
            self.display_error("Invalid host specified.")
        elif not str(self._port_field.text()).isdigit():
            self.display_error("Invalid port specified.")
        else:
            set_options = []

            for field in input_fields:
                set_options.append(field.text())

            loader_options = loaders.get_options(loader_name, set_options)
            loader_options["program_directory"] = program_directory

            stager = launchers.create_stager(server_host, server_port,
                                             loader_options)

            launcher_extension, launcher = launchers.generate(
                launcher_name, stager)
            launcher_path = path.realpath(
                path.join(
                    path.dirname(__file__), path.pardir, path.pardir, "data",
                    "builds", "Launcher-{}.{}".format(
                        str(uuid4())[:6], launcher_extension)))

            with open(launcher_path, "w") as output_file:
                output_file.write(launcher)

            self.display_info(
                "Launcher written to: \n{}".format(launcher_path))
Example #6
0
class WebTab(QWidget):

    class SavedTab(object):
        def __init__(self, webTab=None):
            self.title = ''
            self.url = QUrl()
            self.icon = QIcon()
            self.history = QByteArray()
            self.isPinned = False
            self.zoomLevel = 1
            self.parentTab = -1
            self.childTabs = []
            self.sessionData = {}
            if webTab:
                self.setWebTab(webTab)

        def __getstate__(self):
            result = dict(self.__dict__)
            result['url'] = result['url'].toEncoded()
            data = QByteArray()
            ds = QDataStream(data, QIODevice.WriteOnly)
            ds.writeQVariant(self.icon)
            result['icon'] = data.data()
            return result

        def __setstate__(self, state):
            for key, val in state.items():
                if key == 'url':
                    self.__dict__[key] = QUrl.fromEncoded(val)
                elif key == 'icon':
                    ds = QDataStream(QByteArray(val))
                    self.__dict__[key] = ds.readQVariant()
                else:
                    self.__dict__[key] = val

        def setWebTab(self, webTab):
            self.title = webTab.title()
            self.url = webTab.url()
            self.icon = webTab.icon()
            self.history = webTab.historyData()
            self.isPinned = webTab.isPinned()
            self.zoomLevel = webTab.zoomLevel()
            if webTab.parentTab():
                self.parentTab = webTab.parentTab().tabIndex()
            else:
                self.parentTab = -1
            self.childTabs = [ tab.tabIndex() for tab in webTab.childTabs() ]
            self.sessionData = webTab.sessionData()

        def isValid(self):
            return not self.url.isEmpty() or not self.history.isEmpty()

        def clear(self):
            self.title = ''
            self.url = QUrl()
            self.icon = QIcon()
            self.history = QByteArray()
            self.isPinned = False
            self.zoomLevel = 1
            self.parentTab = -1
            self.childTabs = []
            self.sessionData = {}

    # type AddChildBehavior
    AppendChild = 0
    PrependChild = 1

    s_addChildBehavior = AppendChild

    def __init__(self, parent=None):
        super(WebTab, self).__init__(parent)
        self.setObjectName('webtab')

        self._tabBar = None
        self._window = None
        self._parentTab = None
        self._childTabs = []
        self._sessionData = {}
        self._savedTab = self.SavedTab()
        self._isPinned = False
        self._isCurrentTab = False

        self._webView = TabbedWebView(self)
        self._webView.setPage(WebPage())
        self._webView.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
        self.setFocusProxy(self._webView)

        self._locationBar = LocationBar(self)
        self._locationBar.setWebView(self._webView)

        self._tabIcon = TabIcon(self)
        self._tabIcon.setWebTab(self)

        self._layout = QVBoxLayout(self)
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)
        self._layout.addWidget(self._webView)

        viewWidget = QWidget(self)
        viewWidget.setLayout(self._layout)

        self._splitter = QSplitter(Qt.Vertical, self)
        self._splitter.setChildrenCollapsible(False)
        self._splitter.addWidget(viewWidget)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        layout.addWidget(self._splitter)
        self.setLayout(layout)

        self._notificationWidget = QWidget(self)
        self._notificationWidget.setAutoFillBackground(True)
        pal = self._notificationWidget.palette()
        pal.setColor(QPalette.Window, pal.window().color().darker(110))
        self._notificationWidget.setPalette(pal)

        nlayout = QVBoxLayout(self._notificationWidget)
        nlayout.setSizeConstraint(QLayout.SetMinAndMaxSize)
        nlayout.setContentsMargins(0, 0, 0, 0)
        nlayout.setSpacing(1)

        self._webView.showNotification.connect(self.showNotification)
        self._webView.loadFinished.connect(self.loadFinished)
        self._webView.titleChanged.connect(self.titleWasChanged)
        self._webView.titleChanged.connect(self.titleChanged)
        self._webView.iconChanged.connect(self.iconChanged)

        self._webView.backgroundActivityChanged.connect(self.backgroundActivityChanged)
        self._webView.loadStarted.connect(lambda: self.loadingChanged.emit(True))
        self._webView.loadFinished.connect(lambda: self.loadingChanged.emit(False))

        def pageChanged(page):
            page.audioMutedChanged.connect(self.playingChanged)
            page.recentlyAudibleChanged.connect(self.mutedChanged)

        pageChanged(self._webView.page())
        self._webView.pageChanged.connect(pageChanged)

        def tabIconResized():
            if self._tabBar:
                self._tabBar.update()
        self._tabIcon.resized.connect(tabIconResized)

    def browserWindow(self):
        '''
        @return BrowserWindow
        '''
        return self._window

    def webView(self):
        '''
        @return TabbedWebView
        '''
        return self._webView

    def locationBar(self):
        '''
        @return LocationBar
        '''
        return self._locationBar

    def tabIcon(self):
        '''
        @return TabIcon
        '''
        return self._tabIcon

    def parentTab(self):
        '''
        @return WebTab
        '''
        return self._parentTab

    def setParentTab(self, tab):
        if self._isPinned or self._parentTab == tab:
            return
        if tab and tab.isPinned():
            return

        if self._parentTab:
            index = self._parentTab._childTabs.index(self)
            if index >= 0:
                self._parentTab._childTabs.pop(index)
                self._parentTab.childTabRemoved.emit(self, index)
        self._parentTab = tab

        if tab:
            self._parentTab = None
            tab.addChildTab(self)
        else:
            self.parentTabChanged.emit(self._parentTab)

    def addChildTab(self, tab, index=-1):
        if self._isPinned or not tab or tab.isPinned():
            return

        oldParent = tab._parentTab
        tab._parentTab = self
        if oldParent:
            index = oldParent._childTabs.index(tab)
            if index >= 0:
                oldParent._childTabs.pop(index)
                oldParent.childTabRemoved.emit(tab, index)

        if index < 0 or index > len(self._childTabs):
            index = 0
            if self.addChildBehavior() == self.AppendChild:
                index = len(self._childTabs)
            else:  # PrependChild
                index = 0

        self._childTabs.insert(index, tab)
        self.childTabAdded.emit(tab, index)
        tab.parentTabChanged.emit(self)

    def childTabs(self):
        '''
        @return QVector<WebTab*>
        '''
        return self._childTabs

    def sessionData(self):
        '''
        @return {}
        '''
        return self._sessionData

    def setSessionData(self, key, value):
        self._sessionData[key] = value

    def url(self):
        if self.isRestored():
            if self._webView.url().isEmpty() and self._webView.isLoading():
                return self._webView.page().requestedUrl()
            return self._webView.url()
        else:
            return self._savedTab.url

    def title(self, allowEmpty=False):
        if self.isRestored():
            return self._webView.title(allowEmpty)
        else:
            return self._savedTab.title

    def icon(self, allowNull=False):
        if self.isRestored():
            return self._webView.icon(allowNull)
        if allowNull or not self._savedTab.icon.isNull():
            return self._savedTab.icon
        return IconProvider.emptyWebIcon()

    def history(self):
        '''
        @return QWebEngineHistory
        '''
        return self._webView.history()

    def zoomLevel(self):
        return self._webView.zoomLevel()

    def setZoomLevel(self, level):
        self._webView.setZoomLevel(level)

    def detach(self):
        assert(self._window)
        assert(self._tabBar)

        # Remove from tab tree
        self.removeFromTabTree()

        # Remove icon from tab
        self._tabBar.setTabButton(self.tabIndex(), self._tabBar.iconButtonPosition(), None)
        self._tabIcon.setParent(self)

        # Remove the tab from tabbar
        self._window.tabWidget().removeTab(self.tabIndex())
        self.setParent(None)
        # Remove the locationbar from window
        self._locationBar.setParent(self)
        # Detach TabbedWindow
        self._webView.setBrowserWindow(None)

        if self._isCurrentTab:
            self._isCurrentTab = False
            self.currentTabChanged.emit(self._isCurrentTab)

        self._tabBar.currentChanged.disconnect(self.onCurrentChanged)

        self._window = None
        self._tabBar = None

    def onCurrentChanged(self, index):
        wasCurrent = self._isCurrentTab
        self._isCurrentTab = index == self.tabIndex()
        if wasCurrent != self._isCurrentTab:
            self.currentTabChanged.emit(self._isCurrentTab)

    def attach(self, window):
        self._window = window
        self._tabBar = self._window.tabWidget().tabBar()

        self._webView.setBrowserWindow(self._window)
        self._locationBar.setBrowserWindow(self._window)
        self._tabBar.setTabText(self.tabIndex(), self.title())
        self._tabBar.setTabButton(self.tabIndex(), self._tabBar.iconButtonPosition(), self._tabIcon)
        QTimer.singleShot(0, self._tabIcon.updateIcon)

        self.onCurrentChanged(self._tabBar.currentIndex())
        self._tabBar.currentChanged.connect(self.onCurrentChanged)

    def historyData(self):
        '''
        @return QByteArray
        '''
        if self.isRestored():
            historyArray = QByteArray()
            stream = QDataStream(historyArray, QIODevice.WriteOnly)
            history = self._webView.history()
            stream << history
            return historyArray
        else:
            return self._savedTab.history

    def stop(self):
        self._webView.stop()

    def reload(self):
        self._webView.reload()

    def load(self, request):
        '''
        @param: requset LoadRequest
        '''
        if self.isRestored():
            self.tabActivated()
            QTimer.singleShot(0, lambda: self.load(request))
        else:
            self._webView.load(request)

    def unload(self):
        self._savedTab = self.SavedTab(self)
        self.restoredChanged.emit(self.isRestored())
        self._webView.setPage(WebPage())
        self._webView.setFocus()

    def isLoading(self):
        return self._webView.isloading()

    def isPinned(self):
        return self._isPinned

    def setPinned(self, state):
        if self._isPinned == state:
            return
        if state:
            self.removeFromTabTree()
        self._isPinned = state
        self.pinnedChanged.emit(self._isPinned)

    def togglePinned(self):
        assert(self._tabBar)
        assert(self._window)
        self.setPinned(not self.isPinned())
        self._window.tabWidget().pinUnPinTab(self.tabIndex(), self.title())

    def isMuted(self):
        return self._webView.page().isAudioMuted()

    def isPlaying(self):
        return self._webView.page().recentlyAudible()

    def setMuted(self, muted):
        self._webView.page().setAudioMuted(muted)

    def toggleMuted(self):
        self.setMuted(not self.isMuted())

    def backgroundActivity(self):
        return self._webView.backgroundActivity()

    def tabIndex(self):
        index = -1
        if self._tabBar:
            index = self._tabBar.tabWidget().indexOf(self)
        return index

    def isCurrentTab(self):
        return self._isCurrentTab

    def makeCurrentTab(self):
        if self._tabBar:
            self._tabBar.tabWidget().setCurrentIndex(self.tabIndex())

    def closeTab(self):
        if self._tabBar:
            self._tabBar.tabWidget().closeTab(self.tabIndex())

    def moveTab(self, to):
        if self._tabBar:
            self._tabBar.tabWidget().moveTab(self.tabIndex(), to)

    def haveInspector(self):
        return self._splitter.count() > 1 and self._splitter.widget(1).inherits('WebInspector')

    def showWebInspector(self, inspectElement=False):
        if not WebInspector.isEnabled() or self.haveInspector():
            return

        inspector = WebInspector(self)
        inspector.setView(self._webView)
        if inspectElement:
            inspector.inspectElement()

        height = inspector.sizeHint().height()
        self._splitter.addWidget(inspector)
        self._splitter.setSizes((self._splitter.height() - height, height))

    def toggleWebInspector(self):
        if not self.haveInspector():
            self.showWebInspector()
        else:
            self._splitter.widget(1).destroy()  # TODO: del?

    def showSearchToolBar(self, searchText=''):
        index = 1
        toolBar = None
        if self._layout.count() == 1:
            toolBar = SearchToolBar(self._webView, self)
            self._layout.insertWidget(index, toolBar)
        if self._layout.count() == 2:
            assert(isinstance(self._layout.itemAt(index).widget(), SearchToolBar))
            toolBar = self._layout.itemAt(index).widget()
        assert(toolBar)
        if not searchText:
            toolBar.setText(searchText)
        toolBar.focusSearchLine()

    def isRestored(self):
        return not self._savedTab.isValid()

    def restoreTab(self, tab):
        '''
        @param: tab SavedTab
        '''
        assert(self._tabBar)
        self.setPinned(tab.isPinned)
        self._sessionData = tab.sessionData

        if not self.isPinned() and gVar.appSettings.loadTabsOnActivation:
            self._savedTab = tab
            self.restoredChanged.emit(self.isRestored())
            index = self.tabIndex()

            self._tabBar.setTabText(index, tab.title)
            self._locationBar.showUrl(tab.url)
            self._tabIcon.updateIcon()
        else:
            # This is called only on restore session and restoring tabs
            # immediately crashes QtWebEngine, waiting after initialization is
            # complete fixes it
            QTimer.singleShot(1000, lambda: self.p_restoreTab(tab))

    def p_restoreTab(self, tab):
        '''
        @param: tab SavedTab
        '''
        self.p_restoreTabByUrl(tab.url, tab.history, tab.zoomLevel)

    def p_restoreTabByUrl(self, url, history, zoomLevel):
        self._webView.load(url)

        # Restoring history of internal pages crashes QtWebEngine 5.8
        blacklistedSchemes = ['view-source', 'chrome']

        if (url.scheme() not in blacklistedSchemes):
            stream = QDataStream(history)
            stream >> self._webView.history()

        self._webView.setZoomLevel(zoomLevel)
        self._webView.setFocus()

    def tabActivated(self):
        if self.isRestored():
            return

        def _onTabActivated():
            if self.isRestored():
                return
            self.p_restoreTab(self._savedTab)
            self._savedTab.clear()
            self.restoredChanged.emit(self.isRestored())

        QTimer.singleShot(0, _onTabActivated)

    def addChildBehavior(self):
        '''
        @return AddChildBehavior
        '''
        return self.s_addChildBehavior

    def setAddChildBehavior(self, behavior):
        self.s_addChildBehavior = behavior

    # Q_SLOTS
    @pyqtSlot(QWidget)
    def showNotification(self, notif):
        self._notificationWidget.setParent(self)
        self._notificationWidget.raise_()
        self._notificationWidget.setFixedWidth(self.width())
        self._notificationWidget.layout().addWidget(notif)
        self._notificationWidget.show()
        notif.show()

    @pyqtSlot()
    def loadFinished(self):
        self.titleWasChanged(self._webView.title())

    # Q_SIGNALS
    titleChanged = pyqtSignal(str) # title
    iconChanged = pyqtSignal(QIcon) # icon
    pinnedChanged = pyqtSignal(bool) # pinned
    restoredChanged = pyqtSignal(bool) # restored
    currentTabChanged = pyqtSignal(bool) # current
    loadingChanged = pyqtSignal(bool) # loading
    mutedChanged = pyqtSignal(bool) # muted
    playingChanged = pyqtSignal(bool) # playing
    backgroundActivityChanged = pyqtSignal(bool) # activity
    parentTabChanged = pyqtSignal('PyQt_PyObject') # WebTab*
    childTabAdded = pyqtSignal('PyQt_PyObject', int) # WebTab*, index
    childTabRemoved = pyqtSignal('PyQt_PyObject', int) # WebTab*, index

    def titleWasChanged(self, title):
        if not self._tabBar or not self._window or not title:
            return
        if self._isCurrentTab:
            self._window.setWindowTitle('%s - Demo' % title)
        self._tabBar.setTabText(self.tabIndex(), title)

    # override
    def resizeEvent(self, event):
        QWidget.resizeEvent(self, event)
        self._notificationWidget.setFixedWidth(self.width())

    def removeFromTabTree(self):
        parentTab = self._parentTab
        parentIndex = -1
        if parentTab:
            parentIndex = parentTab._childTabs.index(self)
        self.setParentTab(None)

        idx = 0
        while self._childTabs:
            child = self._childTabs[0]
            child.setParentTab(None)
            if parentTab:
                parentTab.addChildTab(child, parentIndex + idx)
                idx += 1