Beispiel #1
0
    def __init__(self, delphi, campaign, archive_meta=None):
        super().__init__(None)
        self.delphi = delphi
        self.campaign = campaign
        self.archive_meta = archive_meta

        self.dirty = True

        campaign_db_path = self.database_path(campaign)
        self._engine = create_engine("sqlite:///{}".format(campaign_db_path),
                                     echo=True)
        self._Session = sessionmaker(bind=self._engine)

        GameBase.metadata.create_all(self._engine)
        CampaignBase.metadata.create_all(self._engine)

        self.view = CampaignWindow(self.campaign)
        self.map_controller = None
        self.player_controller = None
        self.session_controller = None
        self.search_controller = None
        self._init_subcontrollers()

        asset_tree = self.build_asset_tree()
        self.asset_tree_model = TreeModel(asset_tree)

        self._init_view()
Beispiel #2
0
class CampaignController(QtController):
    """
    A ``CampaignController`` is the controller for a campaign during the
    lifetime of an application. To keep this class small, it is mostly
    responsible for managing the highest level logic on a campaign and
    delegating operations to sub-controllers.

    ``CampaignController`` instances operate on already existing campaigns. The
    creation of, for example, the working directory for the campaign is expected
    to be handled externally, e.g. by the ``AppController`` or test harnesses.
    """
    def __init__(self, delphi, campaign, archive_meta=None):
        super().__init__(None)
        self.delphi = delphi
        self.campaign = campaign
        self.archive_meta = archive_meta

        self.dirty = True

        campaign_db_path = self.database_path(campaign)
        self._engine = create_engine("sqlite:///{}".format(campaign_db_path),
                                     echo=True)
        self._Session = sessionmaker(bind=self._engine)

        GameBase.metadata.create_all(self._engine)
        CampaignBase.metadata.create_all(self._engine)

        self.view = CampaignWindow(self.campaign)
        self.map_controller = None
        self.player_controller = None
        self.session_controller = None
        self.search_controller = None
        self._init_subcontrollers()

        asset_tree = self.build_asset_tree()
        self.asset_tree_model = TreeModel(asset_tree)

        self._init_view()

    def db(self):
        """
        :return: A session to the database.
        """
        self._Session.configure(bind=self._engine)
        return self._Session()

    @staticmethod
    def working_directory(campaign):
        """
        Return an absolute path to the working directory for the campaign,
        usually ``TEMP_DIR/{campaign.id}/``.
        """
        return os.path.join(TMP_PATH, str(campaign.id))

    @staticmethod
    def extracted_archive_path(campaign):
        return os.path.join(CampaignController.working_directory(campaign),
                            "archive")

    @staticmethod
    def database_path(campaign):
        return os.path.join(
            CampaignController.extracted_archive_path(campaign), "campaign.db")

    @staticmethod
    def build_context_menu(listing, name):
        context_menu = QMenu(name)
        for action in listing:
            context_menu.addAction(action)
        return context_menu

    @staticmethod
    def xapian_database_path(campaign):
        return os.path.join(CampaignController.working_directory(campaign),
                            "oracle")

    def _init_subcontrollers(self):
        self.map_controller = MapController(self)
        self.player_controller = PlayerController(self)
        self.note_controller = NoteController(self)
        self.session_controller = SessionController(self)

        self.search_controller = SearchController(self.delphi,
                                                  SearchCompleter())

    def _init_view(self):
        sc = self.search_controller
        v = self.view

        v.save_campaign.triggered.connect(self.on_sync_campaign)
        v.save_campaign_as.triggered.connect(self.on_save_campaign_as)

        v.searchEdit.textChanged.connect(sc.on_search_text_changed)
        v.searchEdit.returnPressed.connect(sc.on_search_requested)

        v.assetTree.setModel(self.asset_tree_model)
        v.assetTree.clicked.connect(lambda idx: log.debug(
            "idx = %s, %s", idx, self.asset_tree_model.rowCount(idx)))
        v.assetTree.doubleClicked.connect(self.asset_tree_doubleclick)
        v.assetTree.customContextMenuRequested.connect(
            self.asset_tree_context_menu_requested)

        v.campaign_properties.triggered.connect(self.on_campaign_properties)

    def build_asset_tree(self):
        root = FixedNode(*[
            controller.tree_node for controller in [
                self.map_controller, self.session_controller,
                self.player_controller, self.note_controller
            ]
        ])
        return root

    def window_moved(self):
        """Called when the main campaign window is moved."""
        self.search_controller.update_results_popup()

    def asset_tree_doubleclick(self, index):
        node = index.internalPointer()
        if node.action:
            node.action(node)
        elif node.parent and node.parent.item_action:
            node.parent.item_action(node)

    @pyqtSlot(QPoint)
    def asset_tree_context_menu_requested(self, point):
        index = self.view.assetTree.indexAt(point)
        node = index.internalPointer()
        if node is None:
            return
        controller = node.delegate
        if not controller:
            log.debug("There is no controller on this node.")
            return
        context_menu = CampaignController.build_context_menu(
            controller.context_menu(), "Asset tree context menu")
        context_menu.exec(controller.view.mapToGlobal(point))

    @pyqtSlot()
    def on_sync_campaign(self):
        log.debug("requested to sync campaign")
        am = self.archive_meta
        if not am:
            self._save_campaign_as()
            return
        path = am.last_seen_path
        if am.last_seen_path and not os.path.exists(am.last_seen_path):
            # TODO why do we do this? I forget the original use case.
            display_warning(
                self.view, "The campaign archive appears to have "
                "been moved or deleted.\n\nPlease "
                "select a new location to save this "
                "archive.")
            path = self._save_campaign_as()
            if not path:
                return
        self._sync_archive_meta(path)
        archive.export(
            self.archive_meta,
            CampaignController.extracted_archive_path(self.campaign),
            am.last_seen_path)

    @pyqtSlot()
    def on_save_campaign_as(self):
        self._save_campaign_as()

    @pyqtSlot()
    def on_campaign_properties(self):
        dlg = CampaignPropertiesDialog(self.campaign, self.view)
        dlg.accepted.connect(lambda: self.on_properties_update(dlg))
        dlg.show()

    @pyqtSlot()
    def on_properties_update(self, propdlg):
        options = propdlg.options
        for k, v in options.items():
            setattr(self.campaign, k, v)

        self.view.setWindowTitle(self.campaign.name)
        self.properties_dialog = None

    def _save_campaign_as(self):
        path = get_save_filename(self.view,
                                 "Save campaign as",
                                 filter_=filters.campaign)
        if not path:
            return
        try:
            self._sync_archive_meta(path)
            archive.export(
                self.archive_meta,
                CampaignController.extracted_archive_path(self.campaign), path)
        except OSError as e:
            log.error("could not export campaign: %s", e)
        else:
            return path

    def _sync_archive_meta(self, path):
        campaign = self.campaign
        self.archive_meta = ArchiveMeta(campaign.id,
                                        campaign.game_system.id,
                                        campaign.name,
                                        campaign.description,
                                        campaign.author,
                                        campaign.creation_date,
                                        campaign.revision_date,
                                        last_seen_path=path)
Beispiel #3
0
def getParentTree(id):
    tree = TreeModel.searchParent(id)
    return jsonify(tree)
Beispiel #4
0
def index():
    userAvailable = TreeModel.getUserAvailable()
    return render_template('tree/tree.html', userAvailable=userAvailable)
Beispiel #5
0
def getUplineTree(id):
    tree = TreeModel.searchNetworkUp(id)
    return jsonify(tree)
Beispiel #6
0
def getDownlineTree(id):
    tree = TreeModel.searchNetworkDown(id)
    return jsonify(tree)
Beispiel #7
0
def getDataTree():
    tree = TreeModel.getTree()
    return jsonify(tree)
Beispiel #8
0
def saveTree():
    try:
        TreeModel.insertTree(request)
    except:
        print('ERRORS')
    return redirect('/')
Beispiel #9
0
 def foomodel(self, foodb):
     root = TableNode(foodb, FooTableClass, text="Foo")
     model = TreeModel(root)
     return model
Beispiel #10
0
def attr_model(attr_tree):
    return TreeModel(attr_tree)
Beispiel #11
0
 def test_flags(self):
     model = TreeModel(FixedNode())
     assert model.flags(QModelIndex()) == (Qt.ItemIsEnabled
                                           | Qt.ItemIsSelectable)
Beispiel #12
0
 def test_title_header_data(self):
     model = TreeModel(FixedNode(), title="FooHeader")
     assert model.headerData(0, Qt.Horizontal) == "FooHeader"
     assert model.headerData(0, Qt.Vertical) == QVariant()
Beispiel #13
0
def tree_model(big_fixed_node_tree):
    return TreeModel(big_fixed_node_tree)