Example #1
0
    def __init__(
        self,
        editable: t.Union[Editable, t.Mapping[str, t.Any]],
        undo_stack: t.Optional[QUndoStack] = None,
    ) -> None:
        super().__init__(
            Context.get_undo_stack() if undo_stack is None else undo_stack)

        self._loading_lock = threading.Lock()
        self._loading_event = threading.Event()
        self._loading = False

        if isinstance(editable, Editable):
            self._editable = editable
            self._serialized = None
        else:
            self._editable = None
            self._serialized = editable

        self._layout = QtWidgets.QVBoxLayout(self)
        self._layout.setContentsMargins(0, 0, 0, 0)

        self._loading_label = None

        if self._editable is None:
            self._loading_label = QtWidgets.QLabel('Loading...')
            self._loading_label.setAlignment(QtCore.Qt.AlignCenter)
            self._layout.addWidget(self._loading_label)
            self.editable_loaded.connect(self._on_loaded)
        else:
            self._layout.addWidget(self._editable)
            self._editable.tab = self
            self._editable.show()
Example #2
0
 def add_editable(self, editable: t.Union[Editable, t.Mapping[str, t.Any]],
                  meta: TabMeta) -> Tab:
     tab = EditorTab(
         editable,
         editable.undo_stack
         if isinstance(editable, Editable) else Context.get_undo_stack(),
     )
     self.addTab(tab, meta.truncated_name)
     self._metas[tab] = meta
     return tab
Example #3
0
    def new_draft(self, draft_id: str) -> None:
        for editable, meta in self._metas.items():
            if meta.key == draft_id:
                self.setCurrentWidget(editable)
                return

        saved_draft = Context.saved_drafts.pop(draft_id, None)

        self.setCurrentWidget(
            self.add_editable(
                (DraftView.load(saved_draft, Context.get_undo_stack())
                 if saved_draft is not None else DraftView(
                     DraftModel(draft_id),
                     Context.get_undo_stack(),
                 )),
                TabMeta(
                    'some draft',
                    key=draft_id,
                ),
            ))
Example #4
0
    def __init__(self, draft_model: DraftModel):
        super().__init__()
        self._undo_stack = Context.get_undo_stack()

        self._draft_model = draft_model

        self._latest_meta_info = PickMetaInfo(draft_model)
        self._head_meta_info = PickMetaInfo(draft_model)
        self._head_meta_info.hide()

        self._countdown = Countdown()
        self._countdown.hide()

        self._picking_info = QtWidgets.QLabel('')
        self._picking_info.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                         QtWidgets.QSizePolicy.Fixed)

        self._booster_scene = CubeScene(
            mode=CubeEditMode.CLOSED,
            scene_type=SceneType.BOOSTER,
        )
        self._booster_view = CubeView(
            scene=self._booster_scene,
            undo_stack=self._undo_stack,
            cube_image_view=BoosterImageView(
                self._undo_stack,
                self._booster_scene,
                self._draft_model,
            ),
        )

        layout = QtWidgets.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        info_bar_layout = QtWidgets.QHBoxLayout()
        info_bar_layout.setContentsMargins(0, 0, 0, 0)

        info_bar_layout.addWidget(self._latest_meta_info)
        info_bar_layout.addWidget(self._head_meta_info)
        info_bar_layout.addStretch()
        info_bar_layout.addWidget(self._picking_info)
        info_bar_layout.addWidget(self._countdown)

        layout.addLayout(info_bar_layout)
        layout.addWidget(self._booster_view)

        self._draft_model.new_head.connect(self._set_pick_point)
        self._draft_model.picked.connect(self._on_picked)
        self._draft_model.received_booster.connect(self._on_receive_booster)
        self._draft_model.boosters_changed.connect(self._on_boosters_changed)
        self._booster_view.cube_image_view.card_double_clicked.connect(
            self._on_card_double_clicked)
Example #5
0
    def new_limited_deck(self, deck: LimitedDeck) -> None:
        key = f'pool-deck-{deck.id}'
        if self._check_for_key(key):
            return

        tab = self.add_editable(
            DeckView(
                DeckModel(
                    list(map(PhysicalCard.from_cubeable, deck.deck.maindeck)),
                    list(map(PhysicalCard.from_cubeable, deck.deck.sideboard)),
                ),
                undo_stack=Context.get_undo_stack(),
            ),
            TabMeta(
                deck.name,
                key=key,
            ),
        )

        self.setCurrentWidget(tab)

        self._sort_opened_view(tab.editable)
Example #6
0
    def new_pool(self, pool: Cube, infinites: Infinites, key: str) -> None:
        for tab, meta in self._metas.items():
            if meta.key == key:
                self.setCurrentWidget(tab)
                return

        tab = self.add_editable(
            PoolView(
                PoolModel(
                    list(map(PhysicalCard.from_cubeable, pool)),
                    infinites=infinites,
                ),
                undo_stack=Context.get_undo_stack(),
            ),
            TabMeta(
                key,
                key=key,
            ),
        )
        self.setCurrentWidget(tab)

        self._sort_opened_view(tab.editable)
Example #7
0
    def __init__(self,
                 deck_scene: CubeScene,
                 *,
                 parent: t.Optional[QtWidgets.QWidget] = None) -> None:
        super().__init__(parent)

        self._deck_scene = deck_scene

        self._undo_stack = Context.get_undo_stack()

        self._hand_scene = CubeScene(
            aligner_type=GridAligner,
            mode=CubeEditMode.CLOSED,
            scene_type=SceneType.SAMPLE_HAND,
        )

        self._hand_view = CubeView(self._hand_scene, self._undo_stack)

        self._draw_hand_button = QtWidgets.QPushButton('Draw Hand')
        self._draw_hand_button.clicked.connect(self.refresh)

        self._create_shortcut(self.refresh, 'h')

        self._draw_card_button = QtWidgets.QPushButton('Draw Card')
        self._draw_card_button.clicked.connect(lambda: self.add_cubeables(1))

        self._create_shortcut(self.add_cubeables, 'd')

        layout = QtWidgets.QVBoxLayout(self)

        control_bar = QtWidgets.QHBoxLayout()
        control_bar.addWidget(self._draw_hand_button)
        control_bar.addWidget(self._draw_card_button)

        layout.addWidget(self._hand_view)
        layout.addLayout(control_bar)
Example #8
0
    def __init__(self):
        super().__init__()

        self._match: t.Optional[ScheduledMatch] = None

        self._participants_model = ListTableModel(ParticipantsSchema())

        self._participants_view: ReadOnlyListTableView[
            TournamentParticipant] = ReadOnlyListTableView()
        self.setFocusProxy(self._participants_view)
        self._participants_view.setModel(self._participants_model)
        self._participants_view.item_selected.connect(
            lambda p: Context.editor.open_limited_deck(p.deck.id))

        self._name_label = QtWidgets.QLabel()
        self._name_label.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                       QtWidgets.QSizePolicy.Fixed)
        self._round_label = QtWidgets.QLabel()
        self._round_label.setSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                        QtWidgets.QSizePolicy.Fixed)

        self._deck_cache: t.MutableMapping[int, t.Optional[LimitedDeck]] = {}

        self._deck_preview_model = DeckModel(mode=CubeEditMode.CLOSED)
        self._deck_preview = DeckView(
            self._deck_preview_model,
            Context.get_undo_stack(),
        )

        self._no_preview_view = QtWidgets.QLabel('No preview selected')
        self._no_preview_view.setAlignment(Qt.AlignCenter)

        self._preview_unavailable_view = QtWidgets.QLabel(
            'Preview unavailable')
        self._preview_unavailable_view.setAlignment(Qt.AlignCenter)

        self._preview_stack = QtWidgets.QStackedWidget()
        self._preview_stack.addWidget(self._deck_preview)
        self._preview_stack.addWidget(self._preview_unavailable_view)
        self._preview_stack.addWidget(self._no_preview_view)
        self._preview_stack.setCurrentWidget(self._no_preview_view)

        self.preview_fetched.connect(self._on_retrieved_deck)
        self._participants_view.current_item_changed.connect(
            self._on_participant_selected)

        self._open_button = QtWidgets.QPushButton('Open')
        self._open_button.clicked.connect(self._on_open_clicked)
        self._open_all_button = QtWidgets.QPushButton('Open All')
        self._open_all_button.clicked.connect(self._on_open_all_clicked)

        layout = QtWidgets.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        top_bar = QtWidgets.QHBoxLayout()
        top_bar.setContentsMargins(5, 0, 5, 0)

        top_bar.addWidget(self._name_label)
        top_bar.addStretch()
        top_bar.addWidget(self._round_label)

        splitter = QtWidgets.QSplitter(Qt.Horizontal)

        participants_view = QtWidgets.QWidget()

        participants_layout = QtWidgets.QVBoxLayout(participants_view)
        participants_layout.setContentsMargins(0, 0, 0, 0)

        participants_control_bar_layout = QtWidgets.QHBoxLayout()
        participants_control_bar_layout.setContentsMargins(0, 0, 0, 0)
        participants_control_bar_layout.addWidget(self._open_button)
        participants_control_bar_layout.addWidget(self._open_all_button)

        participants_layout.addWidget(self._participants_view)
        participants_layout.addLayout(participants_control_bar_layout)

        splitter.addWidget(participants_view)
        splitter.addWidget(self._preview_stack)

        layout.addLayout(top_bar)
        layout.addWidget(splitter)
Example #9
0
def load_editable(serialized: t.Mapping[str, t.Any],
                  undo_stack: t.Optional[QUndoStack] = None) -> Editable:
    return (PoolView if serialized['tab_type'] == TabType.POOL else
            DeckView).load(serialized, undo_stack or Context.get_undo_stack())
Example #10
0
    def open_file(self, path: str, target: t.Type[TabModel] = Deck) -> None:
        for editable, meta in self._metas.items():
            if meta.path == path:
                self.setCurrentWidget(editable)
                return

        file_name = os.path.split(path)[1]
        name, extension = os.path.splitext(file_name)
        extension = extension[1:]
        meta = TabMeta(file_name, path)
        editable = None

        if extension.lower() == 'embd':
            with open(path, 'rb') as f:
                try:
                    tab = self.load_file(pickle.load(f), meta)
                except UnpicklingError:
                    raise FileOpenException('corrupt file')

        elif extension.lower() == 'embp':
            with open(path, 'rb') as f:
                try:
                    tab = self.load_file(pickle.load(f), meta)
                except UnpicklingError:
                    raise FileOpenException('corrupt file')

        else:
            with open(path, 'r') as f:
                try:
                    serializer: TabModelSerializer[t.Union[
                        Deck,
                        Pool]] = TabModelSerializer.extension_to_serializer[(
                            extension, target)]
                except KeyError:
                    raise FileOpenException(
                        'unsupported file type "{}"'.format(extension))

                try:
                    tab_model = serializer.deserialize(f.read())
                except SerializationException:
                    raise FileOpenException()

            if target == Deck:
                editable = DeckView(
                    DeckModel(
                        list(
                            map(PhysicalCard.from_cubeable,
                                tab_model.maindeck)),
                        list(
                            map(PhysicalCard.from_cubeable,
                                tab_model.sideboard)),
                    ),
                    Context.get_undo_stack(),
                )

            elif target == Pool:
                editable = PoolView(
                    PoolModel(list(map(PhysicalCard.from_cubeable,
                                       tab_model)), ),
                    Context.get_undo_stack(),
                )

            else:
                raise FileOpenException(
                    'invalid load target "{}"'.format(target))

            tab = self.add_editable(editable, meta)

        self.setCurrentWidget(tab)

        if editable is not None:
            self._sort_opened_view(editable)

        if not Context.main_window.isActiveWindow() and Context.settings.value(
                'focus_on_open_file', True, bool):
            Context.main_window.raise_()
            Context.main_window.show()
            Context.main_window.activateWindow()
Example #11
0
 def new_deck(self, model: DeckModel) -> Tab:
     return self.add_editable(
         DeckView(model, Context.get_undo_stack()),
         TabMeta('untitled deck'),
     )
Example #12
0
def run():
    sys.excepthook = _get_exception_hook()

    arg_parser = argparse.ArgumentParser(description = 'Edit decks')
    arg_parser.add_argument(
        '-v', '--version',
        action = 'store_true',
        help = 'show version',
    )
    arg_parser.add_argument(
        '-m', '--multi-instance',
        action = 'store_true',
        help = 'allow running in parallel with other instances of Embargo Edit',
    )
    arg_parser.add_argument(
        '-d', '--debug',
        action = 'store_true',
        help = 'debug mode',
    )
    arg_parser.add_argument(
        '-l', '--log-level',
        action = 'store',
        help = 'logging level',
        default = 'debug',
        choices = values.LOGGING_LEVEL_MAP.keys(),
    )
    arg_parser.add_argument(
        '--echo-sql',
        action = 'store_true',
        help = 'Echo sql queries',
    )
    arg_parser.add_argument(
        '-n', '--no-server',
        action = 'store_true',
        help = 'dont start server',
    )
    arg_parser.add_argument(
        '--no-ssl-verify',
        action = 'store_true',
        help = 'disable ssl certificate verification for remote connections.',
    )
    arg_parser.add_argument(
        '--db-type',
        type = str,
        nargs = '?',
        choices = ['sql', 'pickle', 'default'],
        default = 'default',
        help = 'what type of server to use. "default" means use the one defined in application settings',
    )
    arg_parser.add_argument(
        '--port',
        metavar = 'P',
        type = int,
        nargs = '?',
        default = 7777,
        help = 'server port',
    )
    arg_parser.add_argument(
        '--host',
        metavar = 'H',
        type = str,
        nargs = '?',
        default = 'localhost',
        help = 'server host',
    )
    arg_parser.add_argument('files', metavar = 'F', type = str, nargs = '*', help = 'paths of files to open')

    args = arg_parser.parse_args()

    for k, v in logging.Logger.manager.loggerDict.items():
        if isinstance(v, logging.Logger):
            v.handlers[:] = []

    logging.basicConfig(
        format = '%(levelname)s %(message)s',
        level = values.LOGGING_LEVEL_MAP[args.log_level],
        stream = sys.stdout,
    )

    logging.getLogger('PIL.PngImagePlugin').addFilter(FilterAll())

    if args.version:
        print(version_formatted())
        return

    if not args.multi_instance:
        client = EmbargoClient(host = args.host, port = args.port)

        if client.check():
            logging.info('instance already running')
            if args.files:
                for file in args.files:
                    client.open_file(os.path.abspath(file))
            return

    init_aligners()
    app = EmbargoApp.init(sys.argv)
    app.setQuitOnLastWindowClosed(True)

    compiled = __file__ == os.path.split(__file__)[-1]

    db_type = DbType(args.db_type)

    if args.no_ssl_verify:
        logging.warning('Running without ssl verification!')
        requests.packages.urllib3.disable_warnings()

    init_args = {
        'compiled': compiled,
        'debug': args.debug,
        'db_type': db_type,
        'echo_sql': args.echo_sql,
        'no_ssl_verify': args.no_ssl_verify,
    }

    try:
        Context.init(app, **init_args)
    except Exception:
        if not DBUpdateDialog().exec_() == QDialog.Accepted:
            return
        Context.init(app, **init_args)

    EDB.init(echo = args.echo_sql)

    models.create(EDB.engine)

    init_deck_serializers()

    main_window = MainWindow()

    Context.main_window = main_window

    sys.excepthook = _get_exception_hook(main_window)

    if not args.no_server:
        Context.embargo_server = EmbargoServer(host = args.host, port = args.port)
        Context.embargo_server.start()

    main_window.showMaximized()

    if not args.multi_instance:
        save_state_timer = QtCore.QTimer()
        save_state_timer.timeout.connect(main_window.save_state)
        save_state_timer.start(1000 * 60 * 3)

    if settings.AUTO_LOGIN.get_value():
        LOGIN_CONTROLLER.re_login()

    if args.files:
        for path in args.files:
            Context.open_file.emit(path)

    sys.exit(app.exec_())