def __init__(self):
        super(NavigatorDialog, self).__init__(None)

        self.currentRepo = None
        self.reposItem = None
        self.setupUi(self)

        self.repoTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.repoTree.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.repoTree.itemSelectionChanged.connect(self.selectionChanged)
        self.repoTree.customContextMenuRequested.connect(self.showPopupMenu)

        self.comboEndpoint.currentIndexChanged.connect(self.fillTree)

        self.btnAddServer.setIcon(icon("add-server.svg"))
        self.btnEditServer.setIcon(icon("edit-server.svg"))
        self.btnDeleteServer.setIcon(icon("delete-server.svg"))
        self.btnAddRepo.setIcon(icon("add-repository.svg"))
        self.btnRefresh.setIcon(icon("refresh.svg"))

        self.btnAddServer.clicked.connect(self.addGeoGigServer)
        self.btnEditServer.clicked.connect(self.editGeoGigServer)
        self.btnDeleteServer.clicked.connect(self.deleteGeoGigServer)
        self.btnAddRepo.clicked.connect(self.createRepo)
        self.btnRefresh.clicked.connect(self.fillTree)

        self._enableOrDisableButtons()

        if qtVersion < 5:
            self.repoTree.header().setResizeMode(0, QHeaderView.Stretch)
            self.repoTree.header().setResizeMode(1,
                                                 QHeaderView.ResizeToContents)

        self.versionsTree = HistoryViewer()
        layout = QVBoxLayout()
        layout.addWidget(QLabel("Repository history"))
        layout.addWidget(self.versionsTree)
        self.versionsWidget.setLayout(layout)

        def _repoChanged(repo):
            if self.currentRepo is not None and repo.url == self.currentRepo.url:
                self.updateCurrentRepo(repo, True)
            for i in range(self.repoTree.topLevelItemCount()):
                item = self.repoTree.topLevelItem(i)
                if item.repo == repo:
                    item.refreshContent()

        repoWatcher.repoChanged.connect(_repoChanged)

        self.updateNavigator()

        self.repoTree.itemExpanded.connect(self._itemExpanded)
    def __init__(self):
        super(NavigatorDialog, self).__init__(None)

        self.currentRepo = None
        self.reposItem = None
        self.setupUi(self)

        self.repoTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.repoTree.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.repoTree.itemSelectionChanged.connect(self.selectionChanged)
        self.repoTree.customContextMenuRequested.connect(self.showPopupMenu)

        self.comboEndpoint.currentIndexChanged.connect(self.fillTree)

        self.btnAddServer.setIcon(icon("add-server.svg"))
        self.btnEditServer.setIcon(icon("edit-server.svg"))
        self.btnDeleteServer.setIcon(icon("delete-server.svg"))
        self.btnAddRepo.setIcon(icon("add-repository.svg"))
        self.btnRefresh.setIcon(icon("refresh.svg"))

        self.btnAddServer.clicked.connect(self.addGeoGigServer)
        self.btnEditServer.clicked.connect(self.editGeoGigServer)
        self.btnDeleteServer.clicked.connect(self.deleteGeoGigServer)
        self.btnAddRepo.clicked.connect(self.createRepo)
        self.btnRefresh.clicked.connect(self.fillTree)
        self.btnRefresh.clicked.connect(self.refreshTree)

        self._enableOrDisableButtons()

        if qtVersion < 5:
            self.repoTree.header().setResizeMode(0, QHeaderView.Stretch)
            self.repoTree.header().setResizeMode(1, QHeaderView.ResizeToContents)

        self.versionsTree = HistoryViewer()
        layout = QVBoxLayout()
        layout.addWidget(QLabel("Repository history"))
        layout.addWidget(self.versionsTree)
        self.versionsWidget.setLayout(layout)

        def _repoChanged(repo):
            if self.currentRepo is not None and repo.url == self.currentRepo.url:
                self.updateCurrentRepo(repo, True)
            for i in range(self.repoTree.topLevelItemCount()):
                item = self.repoTree.topLevelItem(i)
                if item.repo == repo:
                    item.refreshContent()
        repoWatcher.repoChanged.connect(_repoChanged)

        self.updateNavigator()

        self.repoTree.itemExpanded.connect(self._itemExpanded)
    def __init__(self):
        QtGui.QDialog.__init__(self, config.iface.mainWindow(),
                               QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint)

        self.currentRepo = None
        self.currentRepoName = None
        self.privateVersioReposItem = None
        self.sharedVersioReposItem = None
        self.reposItem = None
        self.localOnlyVersioReposItem = None
        self.ui = Ui_NavigatorDialog()
        self.ui.setupUi(self)

        self.ui.filterBox.adjustSize()
        tabHeight = self.ui.filterBox.height() + self.ui.filterBox.parent().layout().spacing()
        self.ui.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;} QTabBar::tab { height: %ipx}" % tabHeight);

        self.ui.newRepoButton.clicked.connect(self.newRepo)
        self.ui.openButton.clicked.connect(self.openRepo)
        self.ui.filterBox.textChanged.connect(self.filterRepos)
        self.ui.repoTree.itemClicked.connect(self.treeItemClicked)
        self.ui.filterButton.clicked.connect(self.showFilterPopup)
        self.ui.clearFilterButton.clicked.connect(self.clearFilter)
        self.ui.tabWidget.currentChanged.connect(self.tabChanged)
        self.ui.repoTree.customContextMenuRequested.connect(self.showRepoTreePopupMenu)
        self.ui.repoDescription.setOpenLinks(False)
        self.connect(self.ui.repoDescription, QtCore.SIGNAL("anchorClicked(const QUrl&)"),
                     self.descriptionLinkClicked)
        self.ui.repoTree.setFocusPolicy(QtCore.Qt.NoFocus)

        with open(resourceFile("repodescription.css")) as f:
            sheet = "".join(f.readlines())
        self.ui.repoDescription.document().setDefaultStyleSheet(sheet)
        self.ui.repoTree.header().setResizeMode(0, QtGui.QHeaderView.Stretch)
        self.ui.repoTree.header().setResizeMode(1, QtGui.QHeaderView.ResizeToContents)

        self.statusWidget = StatusWidget()
        layout = QtGui.QVBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.statusWidget)
        self.ui.statusWidget.setLayout(layout)

        self.versionsTree = HistoryViewer()
        layout = QtGui.QVBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.versionsTree)
        self.ui.versionsWidget.setLayout(layout)

        self.ui.tabWidget.setCornerWidget(self.ui.filterWidget)
        self.ui.clearFilterButton.setEnabled(False)

        self.versionsTree.headChanged.connect(self.updateBranchLabel)
        self.versionsTree.repoChanged.connect(self.statusWidget.updateLabelText)
        self.statusWidget.repoChanged.connect(self.versionsTree.updateCurrentBranchItem)

        self.lastSelectedRepoItem = None

        self.fillTree()
        self.updateCurrentRepo(None, None)

        self.layersFilterDialog = None
        self.repoLayers = []
class NavigatorDialog(QtGui.QDialog):

    def __init__(self):
        QtGui.QDialog.__init__(self, config.iface.mainWindow(),
                               QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint)

        self.currentRepo = None
        self.currentRepoName = None
        self.privateVersioReposItem = None
        self.sharedVersioReposItem = None
        self.reposItem = None
        self.localOnlyVersioReposItem = None
        self.ui = Ui_NavigatorDialog()
        self.ui.setupUi(self)

        self.ui.filterBox.adjustSize()
        tabHeight = self.ui.filterBox.height() + self.ui.filterBox.parent().layout().spacing()
        self.ui.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;} QTabBar::tab { height: %ipx}" % tabHeight);

        self.ui.newRepoButton.clicked.connect(self.newRepo)
        self.ui.openButton.clicked.connect(self.openRepo)
        self.ui.filterBox.textChanged.connect(self.filterRepos)
        self.ui.repoTree.itemClicked.connect(self.treeItemClicked)
        self.ui.filterButton.clicked.connect(self.showFilterPopup)
        self.ui.clearFilterButton.clicked.connect(self.clearFilter)
        self.ui.tabWidget.currentChanged.connect(self.tabChanged)
        self.ui.repoTree.customContextMenuRequested.connect(self.showRepoTreePopupMenu)
        self.ui.repoDescription.setOpenLinks(False)
        self.connect(self.ui.repoDescription, QtCore.SIGNAL("anchorClicked(const QUrl&)"),
                     self.descriptionLinkClicked)
        self.ui.repoTree.setFocusPolicy(QtCore.Qt.NoFocus)

        with open(resourceFile("repodescription.css")) as f:
            sheet = "".join(f.readlines())
        self.ui.repoDescription.document().setDefaultStyleSheet(sheet)
        self.ui.repoTree.header().setResizeMode(0, QtGui.QHeaderView.Stretch)
        self.ui.repoTree.header().setResizeMode(1, QtGui.QHeaderView.ResizeToContents)

        self.statusWidget = StatusWidget()
        layout = QtGui.QVBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.statusWidget)
        self.ui.statusWidget.setLayout(layout)

        self.versionsTree = HistoryViewer()
        layout = QtGui.QVBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.versionsTree)
        self.ui.versionsWidget.setLayout(layout)

        self.ui.tabWidget.setCornerWidget(self.ui.filterWidget)
        self.ui.clearFilterButton.setEnabled(False)

        self.versionsTree.headChanged.connect(self.updateBranchLabel)
        self.versionsTree.repoChanged.connect(self.statusWidget.updateLabelText)
        self.statusWidget.repoChanged.connect(self.versionsTree.updateCurrentBranchItem)

        self.lastSelectedRepoItem = None

        self.fillTree()
        self.updateCurrentRepo(None, None)

        self.layersFilterDialog = None
        self.repoLayers = []

    def descriptionLinkClicked(self, url):
        url = url.toString()
        if url == "title":
            text, ok = QtGui.QInputDialog.getText(self, 'Title',
                                              'Enter the new repository title:',
                                              text = self.currentRepo.title)
            if ok:
                self.currentRepo.title = text
                self.ui.repoDescription.setText(self.currentRepo.fullDescription)
                self.lastSelectedRepoItem.refreshTitle()

    def fillTree(self):
        self.updateCurrentRepo(None, None)
        self.ui.repoTree.clear()
        self.reposItem = None
        self.privateVersioReposItem = None
        self.sharedVersioReposItem = None
        self.localOnlyVersioReposItem = None
        self.downloadedPublicVersioReposItem = None
        repos = execute(localRepos)

        self.reposItem = OrderedParentItem("Local Repositories", 0)
        self.reposItem.setIcon(0, privateReposIcon)
        for repo in repos:
            item = RepoItem(repo)
            self.reposItem.addChild(item)
        if self.reposItem.childCount():
            self.ui.repoTree.addTopLevelItem(self.reposItem)
            self.filterRepos()
            self.reposItem.setExpanded(True)
        self.ui.repoTree.sortItems(0, QtCore.Qt.AscendingOrder)


    def showFilterPopup(self):
        if self.layersFilterDialog is None:
            self.layersFilterDialog = LayersFilterDialog(self.repoLayers, self.ui.filterButton, self)
            self.layersFilterDialog.filterLayersChanged.connect(self.filterLayersChanged)
            self.layersFilterDialog.filterTextChanged.connect(self.filterTextChanged)
        self.layersFilterDialog.setFilterLayers(self.versionsTree.filterLayers)
        self.layersFilterDialog.setFilterText(self.versionsTree.filterText)
        self.layersFilterDialog.show()

    def clearFilter(self):
        self.versionsTree.filterLayers = None
        self.versionsTree.filterText = ""
        self.ui.clearFilterButton.setEnabled(False)

    def tabChanged(self, i):
        self.ui.filterButton.setVisible(i != 0)

    def filterLayersChanged(self):
        enabled = self.layersFilterDialog.filterText.strip() != "" or self.versionsTree.filterLayers is not None
        self.ui.clearFilterButton.setEnabled(enabled)
        self.versionsTree.filterLayers = self.layersFilterDialog.filterLayers

    def filterTextChanged(self):
        enabled = self.layersFilterDialog.filterText.strip() != "" or self.versionsTree.filterLayers is not None
        self.ui.clearFilterButton.setEnabled(enabled)
        self.versionsTree.filterText = self.layersFilterDialog.filterText

    def showHistoryTab(self):
        self.ui.historyTabButton.setAutoRaise(False)
        self.ui.descriptionTabButton.setAutoRaise(True)
        self.ui.versionsWidget.setVisible(True)
        self.ui.repoDescription.setVisible(False)
        self.ui.filterButton.setVisible(True)
        self.ui.filterButton.setEnabled(len(self.repoLayers) != 0)

    def showDescriptionTab(self):
        self.ui.historyTabButton.setAutoRaise(True)
        self.ui.descriptionTabButton.setAutoRaise(False)
        self.ui.versionsWidget.setVisible(False)
        self.ui.repoDescription.setVisible(True)
        self.ui.filterButton.setVisible(False)

    def showRepoTreePopupMenu(self, point):
        item = self.ui.repoTree.selectedItems()[0]
        if isinstance(item, RepoItem):
            menu = QtGui.QMenu()
            addAction = QtGui.QAction(addIcon, "Add layer to repository...", None)
            addAction.triggered.connect(self.addLayer)
            menu.addAction(addAction)
            addMultipleAction = QtGui.QAction(addIcon, "Add multiple snapshots of a layer to repository...", None)
            addMultipleAction.triggered.connect(self.batchImport)
            menu.addAction(addMultipleAction)
            deleteAction = QtGui.QAction(deleteIcon, "Delete this repository", None)
            deleteAction.triggered.connect(lambda: self.deleteRepo(item))
            menu.addAction(deleteAction)
            deleteAction = QtGui.QAction(deleteIcon, "Delete this repository", None)
            deleteAction.triggered.connect(lambda: self.deleteRepo(item))
            menu.addAction(deleteAction)
            syncAction = QtGui.QAction(syncIcon, "Open Sync dialog for this repository...", None)
            syncAction.triggered.connect(lambda: self.syncRepo(item))
            menu.addAction(syncAction)
            point = self.ui.repoTree.mapToGlobal(point)
            menu.exec_(point)

    def syncRepo(self, item):
        dlg = SyncDialog(item.repo.repo(), item.repo.title)
        dlg.exec_()
        if dlg.conflicts:
            self.statusWidget.updateLabelText()
        if dlg.pulled:
            updateTrackedLayers(item.repo.repo())
            self.versionsTree.updateCurrentBranchItem
            self.statusWidget.updateLabelText()
        elif dlg.pushed:
            self.statusWidget.updateLabelText()


    def batchImport(self):
        dlg = BatchImportDialog(self, repo = self.currentRepo.repo())
        dlg.exec_()
        if dlg.ok:
            self.versionsTree.updateCurrentBranchItem()
            self.statusWidget.updateLabelText()

    def addLayer(self):
        layers = [layer for layer in getVectorLayers()
                        if layer.source().lower().endswith("shp")
                        and not isTracked(layer)]
        if layers:
            dlg = ImportDialog(self, repo = self.currentRepo.repo())
            dlg.exec_()
            if dlg.ok:
                self.versionsTree.updateCurrentBranchItem()
                self.statusWidget.updateLabelText()
        else:
            QtGui.QMessageBox.warning(self, 'Cannot add layer',
                "No suitable layers can be found in your current QGIS project.\n"
                "Open the layers in QGIS before trying to add them.",
                QtGui.QMessageBox.Ok)

    def deleteRepo(self, item):
        ret = QtGui.QMessageBox.warning(config.iface.mainWindow(), "Delete repository",
                        "Are you sure you want to delete this repository?",
                        QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                        QtGui.QMessageBox.Yes);
        if ret == QtGui.QMessageBox.No:
            return
        reponame = item.repo.name
        execute(lambda: deleteRepo(reponame))
        self.lastSelectedRepoItem.parent().removeChild(self.lastSelectedRepoItem)
        if item.parent() == self.sharedVersioReposItem:
            self.lastSelectedRepoItem.setIcon(0, disabledRepoIcon)
        self.updateCurrentRepo(None, None)
        removeTrackedForRepo(item.repo.path)
        killGateway()
        try:
            shutil.rmtree(item.repo.repo().url)
        except:
            ret = QtGui.QMessageBox.warning(config.iface.mainWindow(), "Delete repository",
                    "Local copy of repository could not be removed.\n"
                    "It will have to be removed manually at the following path:\n"
                    + item.repo.repo().url, QtGui.QMessageBox.Ok);


    def openRepo(self, ref):
        exportFullRepo(self.currentRepo.repo())
        loadRepoExportedLayers(self.currentRepo.repo())
        config.iface.messageBar().pushMessage("Repository layers correctly added to QGIS project",
                                                  level = QgsMessageBar.INFO, duration = 4)


    def filterRepos(self):
        text = self.ui.filterBox.text().strip()
        for i in xrange(self.ui.repoTree.topLevelItemCount()):
            parent = self.ui.repoTree.topLevelItem(i)
            for j in xrange(parent.childCount()):
                item = parent.child(j)
                itemText = item.text(0)
                item.setHidden(text != "" and text not in itemText)


    def treeItemClicked(self, item, i):
        if self.lastSelectedRepoItem == item:
            return
        self.lastSelectedRepoItem = item
        if isinstance(item, RepoItem):
            self.updateCurrentRepo(item.repo, item.text(0))
        else:
            self.updateCurrentRepo(None, None)
            url = QtCore.QUrl.fromLocalFile(resourceFile("localrepos_offline.html"))
            self.ui.repoDescription.setSource(url)


    def updateCurrentRepo(self, repo, name):
        def _update():
            if repo != self.currentRepo:
                self.ui.tabWidget.setCurrentIndex(0)
            self.ui.filterButton.setVisible(self.ui.tabWidget.currentIndex() != 0)
            self.ui.tabWidget.setTabEnabled(1, False)
            if repo is None:
                self.currentRepo = None
                self.currentRepoName = None
                self.ui.repoDescription.setText("")
                self.lastSelectedRepoItem = None
                self.ui.openButton.setVisible(False)
                self.ui.repoWidget.setVisible(False)
                self.ui.downloadButton.setVisible(False)
                self.ui.placeholderWidget.setVisible(True)
            else:
                self.currentRepo = repo
                self.currentRepoName = name
                self.ui.repoDescription.setText(repo.fullDescription)
                self.versionsTree.updateContent(repo.repo())
                self.ui.openButton.setVisible(True)
                self.ui.downloadButton.setVisible(False)
                self.updateBranchLabel()
                self.ui.repoWidget.setVisible(True)
                self.ui.placeholderWidget.setVisible(False)
                self.repoLayers = [tree.path for tree in self.currentRepo.repo().trees]
                self.versionsTree.filterLayers = None
                if self.layersFilterDialog is not None:
                    self.layersFilterDialog.setLayers(self.repoLayers)
                self.ui.tabWidget.setTabEnabled(1, True)

            self.statusWidget.updateRepository(repo)
            self.ui.downloadButton.setFixedHeight(self.ui.statusWidget.height())
            self.ui.repoWidget.setFixedHeight(self.ui.statusWidget.height())
            self.ui.placeholderWidget.setFixedHeight(self.ui.statusWidget.height())
        try:
            self.ui.repoTree.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
            self.ui.repoTree.blockSignals(True)
            execute(_update)
        finally:
            self.ui.repoTree.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
            self.ui.repoTree.blockSignals(False)

    def updateBranchLabel(self):
        self.ui.branchLabel.setText("The current branch is <b>%s</b>" % self.versionsTree.head)
        self.ui.repoDescription.setText(self.currentRepo.fullDescription)



    def newRepo(self, name = None):
        title, ok = QtGui.QInputDialog.getText(self, 'Name',
                                          'Enter the new repository name:')
        if ok:
            try:
                repo = execute(lambda : createRepo(title))
                item = RepoItem(RepositoryWrapper(repo.url))
            except Exception, e:
                if "conflict" in unicode(e).lower():
                    text = "A repository with the specified name already exists"
                else:
                    text = "There has been a problem while creating the repository\n" + unicode(e)
                QtGui.QMessageBox.warning(self, "Problem creating repository",
                        text, QtGui.QMessageBox.Ok)
                return

            self.reposItem.addChild(item)
            self.ui.repoTree.addTopLevelItem(self.reposItem)
            self.reposItem.setExpanded(True)
            self.ui.repoTree.sortItems(0, QtCore.Qt.AscendingOrder)
            return repo
Пример #5
0
class NavigatorDialog(BASE, WIDGET):

    def __init__(self):
        super(NavigatorDialog, self).__init__(None)

        self.currentRepo = None
        self.reposItem = None
        self.setupUi(self)

        self.repoTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.repoTree.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.repoTree.itemSelectionChanged.connect(self.selectionChanged)
        self.repoTree.customContextMenuRequested.connect(self.showPopupMenu)

        self.comboEndpoint.currentIndexChanged.connect(self.fillTree)

        self.btnAddServer.setIcon(icon("add-server.svg"))
        self.btnEditServer.setIcon(icon("edit-server.svg"))
        self.btnDeleteServer.setIcon(icon("delete-server.svg"))
        self.btnAddRepo.setIcon(icon("add-repository.svg"))
        self.btnRefresh.setIcon(icon("refresh.svg"))

        self.btnAddServer.clicked.connect(self.addGeoGigServer)
        self.btnEditServer.clicked.connect(self.editGeoGigServer)
        self.btnDeleteServer.clicked.connect(self.deleteGeoGigServer)
        self.btnAddRepo.clicked.connect(self.createRepo)
        self.btnRefresh.clicked.connect(self.fillTree)
        self.btnRefresh.clicked.connect(self.refreshTree)

        self._enableOrDisableButtons()

        if qtVersion < 5:
            self.repoTree.header().setResizeMode(0, QHeaderView.Stretch)
            self.repoTree.header().setResizeMode(1, QHeaderView.ResizeToContents)

        self.versionsTree = HistoryViewer()
        layout = QVBoxLayout()
        layout.addWidget(QLabel("Repository history"))
        layout.addWidget(self.versionsTree)
        self.versionsWidget.setLayout(layout)

        def _repoChanged(repo):
            if self.currentRepo is not None and repo.url == self.currentRepo.url:
                self.updateCurrentRepo(repo, True)
            for i in range(self.repoTree.topLevelItemCount()):
                item = self.repoTree.topLevelItem(i)
                if item.repo == repo:
                    item.refreshContent()
        repoWatcher.repoChanged.connect(_repoChanged)

        self.updateNavigator()

        self.repoTree.itemExpanded.connect(self._itemExpanded)


    def showPopupMenu(self, point):
        item = self.repoTree.currentItem()
        self.menu = item.menu()
        point = self.repoTree.mapToGlobal(point)
        self.menu.popup(point)

    def updateNavigator(self):
        self.fillCombo()
        self.updateCurrentRepo(None)
        #self.checkButtons()

    def _itemExpanded(self, item):
        if item is not None and isinstance(item, (RepoItem, BranchItem)):
            item.populate()

    def _checkoutLayer(self, layername, bbox):
        checkoutLayer(self.currentRepo, layername, bbox)

    def fillCombo(self):
        self.comboEndpoint.clear()
        groups = repository.repoEndpoints.keys()
        #groups.insert(0, "Select a GeoGig server")
        self.comboEndpoint.addItems(groups)

    def refreshTree(self):
        groupName = self.comboEndpoint.currentText()
        repository.refreshEndpoint(groupName)
        self.fillTree()
        
    def fillTree(self):
        groupName = self.comboEndpoint.currentText()
        #repository.refreshEndpoint(groupName)
        self.btnAddRepo.setEnabled(groupName in repository.availableRepoEndpoints)
        self.updateCurrentRepo(None)
        self.repoTree.clear()

        groupRepos = repository.endpointRepos(groupName)
        for repo in groupRepos:
            try:
                item = RepoItem(self, self.repoTree, repo)
                self.repoTree.addTopLevelItem(item)
            except:
                #TODO: inform of failed repos
                pass

        self.repoTree.sortItems(0, Qt.AscendingOrder)

    def selectionChanged(self):
        items = self.repoTree.selectedItems()
        if items:
            self.updateCurrentRepo(items[0].repo)
        else:
            self.updateCurrentRepo(None)

    def updateCurrentRepo(self, repo, force=False):
        if repo == self.currentRepo and not force:
            return
        def _update():
            self.currentRepo = repo
            self.versionsTree.updateContent(repo)
        try:
            self.repoTree.setSelectionMode(QAbstractItemView.NoSelection)
            self.repoTree.blockSignals(True)
            execute(_update)
        finally:
            self.repoTree.setSelectionMode(QAbstractItemView.SingleSelection)
            self.repoTree.blockSignals(False)

    def createRepo(self):
        name, ok = QInputDialog.getText(self, 'Create repository',
                                              'Enter the repository name:')
        if ok:
            group = self.comboEndpoint.currentText()
            url = repository.repoEndpoints[group]
            try:
                repo = execute(lambda: createRepoAtUrl(url, group, name))
            except GeoGigException as e:
                config.iface.messageBar().pushMessage("Error", str(e),
                               level=QgsMessageBar.CRITICAL,
                               duration=5)
                return
            item = RepoItem(self, self.repoTree, repo)
            addRepo(repo)
            self.repoTree.addTopLevelItem(item)
            config.iface.messageBar().pushMessage("Create repository", "Repository correctly created",
                                           level=QgsMessageBar.INFO,
                                           duration=5)

    def editGeoGigServer(self):
        group = self.comboEndpoint.currentText()
        dlg = GeoGigServerDialog(repository.repoEndpoints[group], group)
        dlg.setWindowTitle("Edit GeoGig server")
        dlg.exec_()
        if dlg.title is not None:
            removeRepoEndpoint(group)
            self.comboEndpoint.removeItem(self.comboEndpoint.currentIndex())
            self._addGeoGigServer(dlg.title, dlg.url)

    def deleteGeoGigServer(self):
        group = self.comboEndpoint.currentText()
        res = QMessageBox.question(None,
                                  "Delete server?",
                                  "Are you sure you want to remove the "
                                  "'{}' GeoGig server from the list?".format(group),
                                  QMessageBox.Yes | QMessageBox.No,
                                  QMessageBox.No)
        if res == QMessageBox.Yes:
            removeRepoEndpoint(group)
            self.comboEndpoint.removeItem(self.comboEndpoint.currentIndex())
            self.fillTree()
            self._enableOrDisableButtons()

    def addGeoGigServer(self):
        dlg = GeoGigServerDialog()
        dlg.exec_()
        if dlg.title is not None:
            self._addGeoGigServer(dlg.title, dlg.url)
        self._enableOrDisableButtons()

    def _addGeoGigServer(self, title, url):
        try:
            repos = addRepoEndpoint(url, title)
            if not repos:
                msg = "No repositories found at the specified server"
                QMessageBox.warning(self, 'Add repositories',
                                "No repositories found at the specified server",
                                QMessageBox.Ok)


        except Exception as e:
            msg = "No geogig server found at the specified url. %s"
            QgsMessageLog.logMessage(msg % e, level=QgsMessageLog.CRITICAL)
            QMessageBox.warning(self, 'Add repositories',
                                msg % "See the logs for details.",
                                QMessageBox.Ok)

        self.comboEndpoint.addItem(title)
        self.comboEndpoint.setCurrentIndex(self.comboEndpoint.count() - 1)

    def _enableOrDisableButtons(self):
        self.btnEditServer.setEnabled(len(repository.repoEndpoints) > 0)
        self.btnDeleteServer.setEnabled(len(repository.repoEndpoints) > 0)
    def __init__(self):
        super(NavigatorDialog, self).__init__(None)

        self.currentRepo = None
        self.currentRepoName = None
        self.reposItem = None
        self.setupUi(self)

        self.setAllowedAreas(QtCore.Qt.RightDockWidgetArea | QtCore.Qt.LeftDockWidgetArea)

        self.filterBox.adjustSize()
        tabHeight = self.filterBox.height() + self.filterBox.parent().layout().spacing()
        self.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;} QTabBar::tab { height: %ipx}" % tabHeight);

        self.newRepoButton.clicked.connect(self.newRepo)
        self.openButton.clicked.connect(self.openRepo)
        self.filterBox.textChanged.connect(self.filterRepos)
        self.repoTree.itemClicked.connect(self.treeItemClicked)
        self.filterButton.clicked.connect(self.showFilterPopup)
        self.clearFilterButton.clicked.connect(self.clearFilter)
        self.tabWidget.currentChanged.connect(self.tabChanged)
        self.repoTree.customContextMenuRequested.connect(self.showRepoTreePopupMenu)
        self.repoDescription.setOpenLinks(False)
        self.repoDescription.anchorClicked.connect(self.descriptionLinkClicked)
        self.repoTree.setFocusPolicy(QtCore.Qt.NoFocus)

        with open(resourceFile("repodescription.css")) as f:
            sheet = "".join(f.readlines())
        self.repoDescription.document().setDefaultStyleSheet(sheet)
        self.repoTree.header().setResizeMode(0, QtGui.QHeaderView.Stretch)
        self.repoTree.header().setResizeMode(1, QtGui.QHeaderView.ResizeToContents)

        self.statusWidget = StatusWidget()
        layout = QtGui.QVBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.statusWidget)
        self.repoWidget.setLayout(layout)

        self.versionsTree = HistoryViewer()
        layout = QtGui.QVBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.versionsTree)
        self.versionsWidget.setLayout(layout)

        self.tabWidget.setCornerWidget(self.filterWidget)
        self.clearFilterButton.setEnabled(False)

        self.versionsTree.headChanged.connect(self.statusWidget.updateLabelText)
        self.versionsTree.repoChanged.connect(self.statusWidget.updateLabelText)
        self.statusWidget.repoChanged.connect(self.versionsTree.updateCurrentBranchItem)

        self.lastSelectedRepoItem = None

        def _updateDescription(repo):
            if self.currentRepo is not None and repo.url == self.currentRepo.repo().url:
                self.updateCurrentRepoDescription()
                self.versionsTree.updateCurrentBranchItem()
                self.statusWidget.updateLabelText()
        repoWatcher.repoChanged.connect(_updateDescription)

        self.updateNavigator()
class NavigatorDialog(BASE, WIDGET):

    def __init__(self):
        super(NavigatorDialog, self).__init__(None)

        self.currentRepo = None
        self.currentRepoName = None
        self.reposItem = None
        self.setupUi(self)

        self.setAllowedAreas(QtCore.Qt.RightDockWidgetArea | QtCore.Qt.LeftDockWidgetArea)

        self.filterBox.adjustSize()
        tabHeight = self.filterBox.height() + self.filterBox.parent().layout().spacing()
        self.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;} QTabBar::tab { height: %ipx}" % tabHeight);

        self.newRepoButton.clicked.connect(self.newRepo)
        self.openButton.clicked.connect(self.openRepo)
        self.filterBox.textChanged.connect(self.filterRepos)
        self.repoTree.itemClicked.connect(self.treeItemClicked)
        self.filterButton.clicked.connect(self.showFilterPopup)
        self.clearFilterButton.clicked.connect(self.clearFilter)
        self.tabWidget.currentChanged.connect(self.tabChanged)
        self.repoTree.customContextMenuRequested.connect(self.showRepoTreePopupMenu)
        self.repoDescription.setOpenLinks(False)
        self.repoDescription.anchorClicked.connect(self.descriptionLinkClicked)
        self.repoTree.setFocusPolicy(QtCore.Qt.NoFocus)

        with open(resourceFile("repodescription.css")) as f:
            sheet = "".join(f.readlines())
        self.repoDescription.document().setDefaultStyleSheet(sheet)
        self.repoTree.header().setResizeMode(0, QtGui.QHeaderView.Stretch)
        self.repoTree.header().setResizeMode(1, QtGui.QHeaderView.ResizeToContents)

        self.statusWidget = StatusWidget()
        layout = QtGui.QVBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.statusWidget)
        self.repoWidget.setLayout(layout)

        self.versionsTree = HistoryViewer()
        layout = QtGui.QVBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.versionsTree)
        self.versionsWidget.setLayout(layout)

        self.tabWidget.setCornerWidget(self.filterWidget)
        self.clearFilterButton.setEnabled(False)

        self.versionsTree.headChanged.connect(self.statusWidget.updateLabelText)
        self.versionsTree.repoChanged.connect(self.statusWidget.updateLabelText)
        self.statusWidget.repoChanged.connect(self.versionsTree.updateCurrentBranchItem)

        self.lastSelectedRepoItem = None

        def _updateDescription(repo):
            if self.currentRepo is not None and repo.url == self.currentRepo.repo().url:
                self.updateCurrentRepoDescription()
                self.versionsTree.updateCurrentBranchItem()
                self.statusWidget.updateLabelText()
        repoWatcher.repoChanged.connect(_updateDescription)

        self.updateNavigator()

    def updateNavigator(self):
        self.fillTree()
        self.updateCurrentRepo(None, None)

        self.layersFilterDialog = None
        self.repoLayers = []



    def descriptionLinkClicked(self, url):
        url = url.toString()
        if url == "title":
            text, ok = QtGui.QInputDialog.getText(self, 'Title',
                                              'Enter the new repository title:',
                                              text = self.currentRepo.title)
            if ok:
                self.currentRepo.title = text
                self.updateCurrentRepoDescription()
                self.lastSelectedRepoItem.refreshTitle()

    def updateCurrentRepoDescription(self):
        self.repoDescription.setText(self.currentRepo.fullDescription)

    def fillTree(self):
        self.updateCurrentRepo(None, None)
        self.repoTree.clear()
        self.reposItem = None
        repos = execute(localRepos)

        self.reposItem = OrderedParentItem("Local Repositories", 0)
        self.reposItem.setIcon(0, privateReposIcon)
        for repo in repos:
            item = RepoItem(repo)
            self.reposItem.addChild(item)
        if self.reposItem.childCount():
            self.repoTree.addTopLevelItem(self.reposItem)
            self.filterRepos()
            self.reposItem.setExpanded(True)
        self.repoTree.sortItems(0, QtCore.Qt.AscendingOrder)


    def showFilterPopup(self):
        if self.layersFilterDialog is None:
            self.layersFilterDialog = LayersFilterDialog(self.repoLayers, self.filterButton, self)
            self.layersFilterDialog.filterLayersChanged.connect(self.filterLayersChanged)
            self.layersFilterDialog.filterTextChanged.connect(self.filterTextChanged)
        self.layersFilterDialog.setFilterLayers(self.versionsTree.filterLayers)
        self.layersFilterDialog.setFilterText(self.versionsTree.filterText)
        self.layersFilterDialog.show()

    def clearFilter(self):
        self.versionsTree.filterLayers = None
        self.versionsTree.filterText = ""
        self.clearFilterButton.setEnabled(False)

    def tabChanged(self, i):
        self.filterWidget.setVisible(i != 0)

    def filterLayersChanged(self):
        enabled = self.layersFilterDialog.filterText.strip() != "" or self.versionsTree.filterLayers is not None
        self.clearFilterButton.setEnabled(enabled)
        self.versionsTree.filterLayers = self.layersFilterDialog.filterLayers

    def filterTextChanged(self):
        enabled = self.layersFilterDialog.filterText.strip() != "" or self.versionsTree.filterLayers is not None
        self.clearFilterButton.setEnabled(enabled)
        self.versionsTree.filterText = self.layersFilterDialog.filterText

    def showHistoryTab(self):
        self.historyTabButton.setAutoRaise(False)
        self.descriptionTabButton.setAutoRaise(True)
        self.versionsWidget.setVisible(True)
        self.repoDescription.setVisible(False)
        self.filterWidget.setVisible(True)
        self.filterButton.setEnabled(len(self.repoLayers) != 0)

    def showDescriptionTab(self):
        self.historyTabButton.setAutoRaise(True)
        self.descriptionTabButton.setAutoRaise(False)
        self.versionsWidget.setVisible(False)
        self.repoDescription.setVisible(True)
        self.filterWidget.setVisible(False)

    def showRepoTreePopupMenu(self, point):
        item = self.repoTree.selectedItems()[0]
        if isinstance(item, RepoItem):
            menu = QtGui.QMenu()
            addAction = QtGui.QAction(addIcon, "Add layer to repository...", None)
            addAction.triggered.connect(self.addLayer)
            menu.addAction(addAction)
            addMultipleAction = QtGui.QAction(addIcon, "Add multiple snapshots of a layer to repository...", None)
            addMultipleAction.triggered.connect(self.batchImport)
            menu.addAction(addMultipleAction)
            deleteAction = QtGui.QAction(deleteIcon, "Delete this repository", None)
            deleteAction.triggered.connect(lambda: self.deleteRepo(item))
            menu.addAction(deleteAction)
            deleteAction = QtGui.QAction(deleteIcon, "Delete this repository", None)
            deleteAction.triggered.connect(lambda: self.deleteRepo(item))
            menu.addAction(deleteAction)
            syncAction = QtGui.QAction(syncIcon, "Open Sync dialog for this repository...", None)
            syncAction.triggered.connect(lambda: self.syncRepo(item))
            menu.addAction(syncAction)
            point = self.repoTree.mapToGlobal(point)
            menu.exec_(point)

    def syncRepo(self, item):
        dlg = SyncDialog(item.repo.repo(), item.repo.title)
        dlg.exec_()
        if dlg.conflicts:
            self.statusWidget.updateLabelText()
        if dlg.pulled:
            updateTrackedLayers(item.repo.repo())
            self.versionsTree.updateCurrentBranchItem()
            self.statusWidget.updateLabelText()
        elif dlg.pushed:
            self.statusWidget.updateLabelText()
        self.updateCurrentRepoDescription()

    def batchImport(self):
        dlg = BatchImportDialog(self, repo = self.currentRepo.repo())
        dlg.exec_()
        if dlg.ok:
            self.versionsTree.updateCurrentBranchItem()
            self.statusWidget.updateLabelText()
            self.updateCurrentRepoDescription()

    def addLayer(self):
        layers = [layer for layer in getVectorLayers()
                        if layer.source().lower().endswith("shp")
                        and not isTracked(layer)]
        if layers:
            dlg = ImportDialog(self, repo = self.currentRepo.repo())
            dlg.exec_()
            if dlg.ok:
                self.versionsTree.updateCurrentBranchItem()
                self.statusWidget.updateLabelText()
                self.updateCurrentRepoDescription()
                setAsTracked(dlg.layer)
        else:
            QtGui.QMessageBox.warning(self, 'Cannot add layer',
                "No suitable layers can be found in your current QGIS project.\n"
                "Open the layers in QGIS before trying to add them.",
                QtGui.QMessageBox.Ok)

    def deleteRepo(self, item):
        ret = QtGui.QMessageBox.warning(config.iface.mainWindow(), "Delete repository",
                        "Are you sure you want to delete this repository?",
                        QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                        QtGui.QMessageBox.Yes);
        if ret == QtGui.QMessageBox.No:
            return
        self.lastSelectedRepoItem.parent().removeChild(self.lastSelectedRepoItem)
        self.updateCurrentRepo(None, None)
        tracked = getTrackedPathsForRepo(item.repo.repo())
        layers = getVectorLayers()
        for layer in layers:
            if layer.source() in tracked:
                setAsUntracked(layer)
        removeTrackedForRepo(item.repo.path)
        killGateway()
        try:
            shutil.rmtree(item.repo.repo().url)
        except:
            ret = QtGui.QMessageBox.warning(config.iface.mainWindow(), "Delete repository",
                    "Local copy of repository could not be removed.\n"
                    "It will have to be removed manually at the following path:\n"
                    + item.repo.repo().url, QtGui.QMessageBox.Ok);


    def openRepo(self, ref):
        exportFullRepo(self.currentRepo.repo())
        loadRepoExportedLayers(self.currentRepo.repo())
        config.iface.messageBar().pushMessage("Repository layers correctly added to QGIS project",
                                                  level = QgsMessageBar.INFO, duration = 4)


    def filterRepos(self):
        text = self.filterBox.text().strip()
        for i in xrange(self.repoTree.topLevelItemCount()):
            parent = self.repoTree.topLevelItem(i)
            for j in xrange(parent.childCount()):
                item = parent.child(j)
                itemText = item.text(0)
                item.setHidden(text != "" and text not in itemText)


    def treeItemClicked(self, item, i):
        if self.lastSelectedRepoItem == item:
            return
        self.lastSelectedRepoItem = item
        if isinstance(item, RepoItem):
            self.updateCurrentRepo(item.repo, item.text(0))
        else:
            self.updateCurrentRepo(None, None)
            url = QtCore.QUrl.fromLocalFile(resourceFile("localrepos_offline.html"))
            self.repoDescription.setSource(url)


    def updateCurrentRepo(self, repo, name):
        def _update():
            if repo != self.currentRepo:
                self.tabWidget.setCurrentIndex(0)
            self.filterWidget.setVisible(self.tabWidget.currentIndex() != 0)
            self.tabWidget.setTabEnabled(1, False)
            if repo is None:
                self.currentRepo = None
                self.currentRepoName = None
                self.repoDescription.setText("")
                self.lastSelectedRepoItem = None
                self.openButton.setEnabled(False)
            else:
                self.currentRepo = repo
                self.currentRepoName = name
                self.repoDescription.setText(repo.fullDescription)
                self.versionsTree.updateContent(repo.repo())
                self.openButton.setEnabled(True)
                self.repoLayers = [tree.path for tree in self.currentRepo.repo().trees]
                self.versionsTree.filterLayers = None
                if self.layersFilterDialog is not None:
                    self.layersFilterDialog.setLayers(self.repoLayers)
                self.tabWidget.setTabEnabled(1, True)

            self.statusWidget.updateRepository(repo)
        try:
            self.repoTree.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
            self.repoTree.blockSignals(True)
            execute(_update)
        finally:
            self.repoTree.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
            self.repoTree.blockSignals(False)

    def newRepo(self, name = None):
        title, ok = QtGui.QInputDialog.getText(self, 'Name',
                                          'Enter the new repository name:')
        if ok:
            try:
                repo = execute(lambda : createRepo(title))
                item = RepoItem(RepositoryWrapper(repo.url))
            except Exception, e:
                if "conflict" in unicode(e).lower():
                    text = "A repository with the specified name already exists"
                else:
                    text = "There has been a problem while creating the repository\n" + unicode(e)
                QtGui.QMessageBox.warning(self, "Problem creating repository",
                        text, QtGui.QMessageBox.Ok)
                return

            self.reposItem.addChild(item)
            self.repoTree.addTopLevelItem(self.reposItem)
            self.reposItem.setExpanded(True)
            self.repoTree.sortItems(0, QtCore.Qt.AscendingOrder)
            return repo
Пример #8
0
    def __init__(self):
        super(NavigatorDialog, self).__init__(None)

        self.currentRepo = None
        self.reposItem = None
        self.setupUi(self)

        self.filterWidget.hide()
        self.leFilter.setPlaceholderText(
            self.tr("Type here to filter repositories..."))

        self.actionAddGeoGigServer.setIcon(icon('geogig_server.svg'))
        self.actionCreateRepository.setIcon(icon('new-repo.png'))
        self.actionAddLayer.setIcon(icon('layer_group.svg'))
        self.actionManageRemotes.setIcon(icon('geogig.png'))
        self.actionEdit.setIcon(icon('edit.svg'))
        self.actionRefresh.setIcon(
            QgsApplication.getThemeIcon('/mActionDraw.svg'))
        self.actionShowFilter.setIcon(
            QgsApplication.getThemeIcon('/mActionFilter2.svg'))
        self.actionDelete.setIcon(
            QgsApplication.getThemeIcon('/mActionDeleteSelected.svg'))
        self.actionHelp.setIcon(
            QgsApplication.getThemeIcon('/mActionHelpContents.svg'))
        self.actionPull.setIcon(icon('pull.svg'))
        self.actionPush.setIcon(icon('push.svg'))

        self.actionAddGeoGigServer.triggered.connect(self.addGeoGigServer)
        self.actionCreateRepository.triggered.connect(self.createRepo)
        self.actionAddLayer.triggered.connect(self.addLayer)
        self.actionEdit.triggered.connect(self.editGeoGigServer)
        self.actionRefresh.triggered.connect(self.updateNavigator)
        self.actionShowFilter.triggered.connect(self.showFilterWidget)
        self.actionDelete.triggered.connect(self.deleteCurrentElement)
        self.actionHelp.triggered.connect(self.openHelp)
        self.actionManageRemotes.triggered.connect(self.manageRemotes)
        self.actionPull.triggered.connect(self.pull)
        self.actionPush.triggered.connect(self.push)

        self.leFilter.returnPressed.connect(self.filterRepos)
        self.leFilter.cleared.connect(self.filterRepos)
        self.leFilter.textChanged.connect(self.filterRepos)

        self.repoTree.itemSelectionChanged.connect(self.selectionChanged)
        self.repoDescription.anchorClicked.connect(self.descriptionLinkClicked)
        self.repoDescription.setOpenLinks(False)
        self.repoTree.setFocusPolicy(Qt.NoFocus)

        with open(resourceFile("repodescription.css")) as f:
            sheet = "".join(f.readlines())
        self.repoDescription.document().setDefaultStyleSheet(sheet)
        if qtVersion < 5:
            self.repoTree.header().setResizeMode(0, QHeaderView.Stretch)
            self.repoTree.header().setResizeMode(1,
                                                 QHeaderView.ResizeToContents)

        self.versionsTree = HistoryViewer()
        layout = QVBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.versionsTree)
        self.versionsWidget.setLayout(layout)

        def _repoChanged(repo):
            if self.currentRepo is not None and repo.url == self.currentRepo.url:
                self.updateCurrentRepo(repo)
            for i in range(self.reposItem.childCount()):
                item = self.reposItem.child(i)
                for j in range(item.childCount()):
                    subitem = item.child(j)
                    if subitem.repo == repo:
                        subitem.refreshContent()

        repoWatcher.repoChanged.connect(_repoChanged)

        self.updateNavigator()

        self.repoTree.itemExpanded.connect(self._itemExpanded)
Пример #9
0
class NavigatorDialog(BASE, WIDGET):
    def __init__(self):
        super(NavigatorDialog, self).__init__(None)

        self.currentRepo = None
        self.reposItem = None
        self.setupUi(self)

        self.filterWidget.hide()
        self.leFilter.setPlaceholderText(
            self.tr("Type here to filter repositories..."))

        self.actionAddGeoGigServer.setIcon(icon('geogig_server.svg'))
        self.actionCreateRepository.setIcon(icon('new-repo.png'))
        self.actionAddLayer.setIcon(icon('layer_group.svg'))
        self.actionManageRemotes.setIcon(icon('geogig.png'))
        self.actionEdit.setIcon(icon('edit.svg'))
        self.actionRefresh.setIcon(
            QgsApplication.getThemeIcon('/mActionDraw.svg'))
        self.actionShowFilter.setIcon(
            QgsApplication.getThemeIcon('/mActionFilter2.svg'))
        self.actionDelete.setIcon(
            QgsApplication.getThemeIcon('/mActionDeleteSelected.svg'))
        self.actionHelp.setIcon(
            QgsApplication.getThemeIcon('/mActionHelpContents.svg'))
        self.actionPull.setIcon(icon('pull.svg'))
        self.actionPush.setIcon(icon('push.svg'))

        self.actionAddGeoGigServer.triggered.connect(self.addGeoGigServer)
        self.actionCreateRepository.triggered.connect(self.createRepo)
        self.actionAddLayer.triggered.connect(self.addLayer)
        self.actionEdit.triggered.connect(self.editGeoGigServer)
        self.actionRefresh.triggered.connect(self.updateNavigator)
        self.actionShowFilter.triggered.connect(self.showFilterWidget)
        self.actionDelete.triggered.connect(self.deleteCurrentElement)
        self.actionHelp.triggered.connect(self.openHelp)
        self.actionManageRemotes.triggered.connect(self.manageRemotes)
        self.actionPull.triggered.connect(self.pull)
        self.actionPush.triggered.connect(self.push)

        self.leFilter.returnPressed.connect(self.filterRepos)
        self.leFilter.cleared.connect(self.filterRepos)
        self.leFilter.textChanged.connect(self.filterRepos)

        self.repoTree.itemSelectionChanged.connect(self.selectionChanged)
        self.repoDescription.anchorClicked.connect(self.descriptionLinkClicked)
        self.repoDescription.setOpenLinks(False)
        self.repoTree.setFocusPolicy(Qt.NoFocus)

        with open(resourceFile("repodescription.css")) as f:
            sheet = "".join(f.readlines())
        self.repoDescription.document().setDefaultStyleSheet(sheet)
        if qtVersion < 5:
            self.repoTree.header().setResizeMode(0, QHeaderView.Stretch)
            self.repoTree.header().setResizeMode(1,
                                                 QHeaderView.ResizeToContents)

        self.versionsTree = HistoryViewer()
        layout = QVBoxLayout()
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.addWidget(self.versionsTree)
        self.versionsWidget.setLayout(layout)

        def _repoChanged(repo):
            if self.currentRepo is not None and repo.url == self.currentRepo.url:
                self.updateCurrentRepo(repo)
            for i in range(self.reposItem.childCount()):
                item = self.reposItem.child(i)
                for j in range(item.childCount()):
                    subitem = item.child(j)
                    if subitem.repo == repo:
                        subitem.refreshContent()

        repoWatcher.repoChanged.connect(_repoChanged)

        self.updateNavigator()

        self.repoTree.itemExpanded.connect(self._itemExpanded)

    def descriptionLinkClicked(self, url):
        url = url.toString()
        if url.startswith("checkout"):
            layernames = url[url.find(":") + 1:].split(",")
            for layername in layernames:
                if layername:
                    try:
                        self._checkoutLayer(layername, None)
                    except HasLocalChangesError:
                        QMessageBox.warning(
                            config.iface.mainWindow(), 'Cannot change version',
                            "There are local changes that would be overwritten.\n"
                            "Revert them before changing version.",
                            QMessageBox.Ok)

    def updateNavigator(self):
        readRepos()
        self.fillTree()
        self.updateCurrentRepo(None)
        self.checkButtons()

    def _itemExpanded(self, item):
        if item is not None and isinstance(item, (RepoItem, BranchItem)):
            item.populate()

    def _removeLayer(self, layeritem):
        user, email = config.getUserInfo()
        if user is None:
            return

        self.currentRepo.removetree(layeritem.layer, user, email,
                                    layeritem.branch)

        config.iface.messageBar().pushMessage(
            "Layer correctly removed from repository",
            level=QgsMessageBar.INFO,
            duration=5)

        layer = getProjectLayerForGeoGigLayer(self.currentRepo.url,
                                              layeritem.layer)
        if layer:
            branches = self.currentRepo.branches()
            layerInRepo = False
            for branch in branches:
                layers = self.currentRepo.trees(branch)
                if layeritem.layer in layers:
                    layerInRepo = True
                    break
            if not layerInRepo:
                setAsNonRepoLayer(layer)
                tracking = getTrackingInfoForGeogigLayer(
                    self.currentRepo.url, layeritem.layer)
                if tracking:
                    removeTrackedLayer(tracking.source)
        #TODO remove triggers from layer
        repoWatcher.repoChanged.emit(self.currentRepo)

    def _checkoutLayer(self, layername, bbox):
        checkoutLayer(self.currentRepo, layername, bbox)

    def fillTree(self):
        self.updateCurrentRepo(None)
        self.repoTree.clear()
        self.reposItem = None
        repos = repository.repos

        self.reposItem = RepositoriesItem()
        self.reposItem.setIcon(0, repoIcon)
        groupedRepos = defaultdict(list)
        for repo in repos:
            groupedRepos[repo.group].append(repo)

        for groupName in repository.repoEndpoints:
            groupRepos = groupedRepos.get(groupName, [])
            groupItem = GroupItem(groupName)
            for repo in groupRepos:
                try:
                    item = RepoItem(self.repoTree, repo)
                    groupItem.addChild(item)
                except:
                    #TODO: inform of failed repos
                    pass

            self.reposItem.addChild(groupItem)

        self.repoTree.addTopLevelItem(self.reposItem)
        if self.reposItem.childCount():
            self.filterRepos()
        self.reposItem.setExpanded(True)
        for i in range(self.reposItem.childCount()):
            self.reposItem.child(i).setExpanded(True)
        #self.repoTree.expandAll()
        self.repoTree.sortItems(0, Qt.AscendingOrder)

    def showHistoryTab(self):
        self.historyTabButton.setAutoRaise(False)
        self.descriptionTabButton.setAutoRaise(True)
        self.versionsWidget.setVisible(True)
        self.repoDescription.setVisible(False)

    def showDescriptionTab(self):
        self.historyTabButton.setAutoRaise(True)
        self.descriptionTabButton.setAutoRaise(False)
        self.versionsWidget.setVisible(False)
        self.repoDescription.setVisible(True)

    def addLayer(self):
        layers = [
            layer for layer in getVectorLayers()
            if layer.source().lower().split("|")[0].split(".")[-1] in
            ["gpkg", "geopkg"] and not isRepoLayer(layer)
        ]
        if layers:
            dlg = ImportDialog(self, repo=self.currentRepo)
            dlg.exec_()
            if dlg.ok:
                #self.versionsTree.updateCurrentBranchItem()
                setAsRepoLayer(dlg.layer)
                repoWatcher.repoChanged.emit(self.currentRepo)
        else:
            QMessageBox.warning(
                self, 'Cannot add layer',
                "No suitable layers can be found in your current QGIS project.\n"
                "Only Geopackage layers that do not already belong to a repository can be added.",
                QMessageBox.Ok)

    def deleteCurrentElement(self):
        if len(self.repoTree.selectedItems()) == 0:
            return

        item = self.repoTree.selectedItems()[0]
        if isinstance(item, RepoItem):
            ret = QMessageBox.warning(
                config.iface.mainWindow(), "Remove repository",
                "Are you sure you want to remove this repository and all the data in it?",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
            if ret == QMessageBox.No:
                return
            tracked = getTrackedPathsForRepo(item.repo)
            item.repo.delete()
            removeRepo(item.repo)
            removeTrackedForRepo(item.repo)
            layers = getVectorLayers()
            for layer in layers:
                if formatSource(layer) in tracked:
                    setAsNonRepoLayer(layer)
            parent = item.parent()
            parent.removeChild(item)
            self.updateCurrentRepo(None)
        elif isinstance(item, GroupItem):
            self._removeRepoEndpoint(item)
        elif isinstance(item, BranchItem):
            ret = QMessageBox.question(
                self, 'Delete branch',
                'Are you sure you want to delete this branch?',
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if ret == QMessageBox.No:
                return
            item.repo.deletebranch(item.branch)
            repoWatcher.repoChanged.emit(item.repo)

        elif isinstance(item, LayerItem):
            ret = QMessageBox.question(
                self, 'Delete layer',
                'Are you sure you want to delete this layer from the selected branch?',
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if ret == QMessageBox.No:
                return
            execute(lambda: self._removeLayer(item))

    def _removeRepoEndpoint(self, item):
        parent = item.parent()
        parent.removeChild(item)
        removeRepoEndpoint(item.text(0))

    def filterRepos(self):
        text = self.leFilter.text().strip()
        for i in range(self.repoTree.topLevelItemCount()):
            parent = self.repoTree.topLevelItem(i)
            for j in range(parent.childCount()):
                item = parent.child(j)
                itemText = item.text(0)
                item.setHidden(text != "" and text not in itemText)

    def selectionChanged(self):
        self.checkButtons()
        items = self.repoTree.selectedItems()
        if items:
            item = items[0]
            try:
                if isinstance(item, (GroupItem, RepositoriesItem)):
                    self.updateCurrentRepo(None)
                    url = QUrl.fromLocalFile(
                        resourceFile("localrepos_offline.html"))
                    self.repoDescription.setSource(url)
                else:
                    if item.repo != self.currentRepo:
                        self.updateCurrentRepo(item.repo)

            except Exception as e:
                msg = "An error occurred while fetching repository data! %s"
                QgsMessageLog.logMessage(msg % e, level=QgsMessageLog.CRITICAL)
                QMessageBox.warning(self, 'Add repositories',
                                    msg % "See the logs for details.",
                                    QMessageBox.Ok)
        else:
            self.updateCurrentRepo(None)

    def updateCurrentRepo(self, repo):
        def _update():
            if repo != self.currentRepo:
                self.tabWidget.setCurrentIndex(0)
            if repo is None:
                self.tabWidget.setTabEnabled(1, False)
                self.currentRepo = None
                self.repoDescription.setText("")
            else:
                self.currentRepo = repo
                self.repoDescription.setText(repo.fullDescription())
                self.versionsTree.updateContent(repo)
                self.tabWidget.setTabEnabled(1, True)

        try:
            self.checkButtons()
            self.repoTree.setSelectionMode(QAbstractItemView.NoSelection)
            self.repoTree.blockSignals(True)
            execute(_update)
        finally:
            self.repoTree.setSelectionMode(QAbstractItemView.SingleSelection)
            self.repoTree.blockSignals(False)

    def createRepo(self):
        name, ok = QInputDialog.getText(self, 'Create repository',
                                        'Enter the repository name:')
        if ok:
            groupItem = self.repoTree.selectedItems()[0]
            group = groupItem.text(0)
            url = repository.repoEndpoints[group]
            try:
                repo = execute(lambda: createRepoAtUrl(url, group, name))
            except GeoGigException as e:
                config.iface.messageBar().pushMessage(
                    "Error", str(e), level=QgsMessageBar.CRITICAL, duration=5)
                return
            item = RepoItem(self.repoTree, repo)
            addRepo(repo)
            groupItem.addChild(item)
            config.iface.messageBar().pushMessage(
                "Create repository",
                "Repository correctly created",
                level=QgsMessageBar.INFO,
                duration=5)

    def editGeoGigServer(self):
        item = self.repoTree.selectedItems()[0]
        dlg = GeoGigServerDialog(repository.repoEndpoints[item.name],
                                 item.name)
        dlg.exec_()
        if dlg.title is not None:
            self._removeRepoEndpoint(item)
            self._addGeoGigServer(dlg.title, dlg.url)

    def addGeoGigServer(self):
        dlg = GeoGigServerDialog()
        dlg.exec_()
        if dlg.title is not None:
            self._addGeoGigServer(dlg.title, dlg.url)

    def _addGeoGigServer(self, title, url):
        try:
            repos = addRepoEndpoint(url, title)
            if not repos:
                msg = "No repositories found at the specified server"
                QMessageBox.warning(
                    self, 'Add repositories',
                    "No repositories found at the specified server",
                    QMessageBox.Ok)
                groupItem = GroupItem(title)
            else:
                groupItem = GroupItem(title)
                for repo in repos:
                    item = RepoItem(self.repoTree, repo)
                    groupItem.addChild(item)

        except Exception as e:
            msg = "No geogig server found at the specified url. %s"
            QgsMessageLog.logMessage(msg % e, level=QgsMessageLog.CRITICAL)
            QMessageBox.warning(self, 'Add repositories',
                                msg % "See the logs for details.",
                                QMessageBox.Ok)
            groupItem = GroupItem(title)
        self.reposItem.addChild(groupItem)
        self.reposItem.setExpanded(True)
        self.repoTree.sortItems(0, Qt.AscendingOrder)

    def showFilterWidget(self, visible):
        self.filterWidget.setVisible(visible)
        if not visible:
            self.leFilter.setText("")
            self.filterRepos()
        else:
            self.leFilter.setFocus()

    def checkButtons(self):
        self.actionCreateRepository.setEnabled(False)
        self.actionRefresh.setEnabled(False)
        self.actionDelete.setEnabled(False)
        self.actionEdit.setEnabled(False)
        self.actionPush.setEnabled(False)
        self.actionPull.setEnabled(False)
        self.actionManageRemotes.setEnabled(False)
        if len(self.repoTree.selectedItems()) == 0:
            return

        item = self.repoTree.selectedItems()[0]
        if isinstance(item, RepositoriesItem):
            self.actionRefresh.setEnabled(True)
        elif isinstance(item, GroupItem):
            self.actionEdit.setEnabled(True)
            if item.isRepoAvailable:
                self.actionCreateRepository.setEnabled(True)
            self.actionDelete.setEnabled(True)
        elif isinstance(item, BranchItem):
            self.actionDelete.setEnabled(item.parent().childCount() > 1
                                         and item.branch != "master")
        elif isinstance(item, RepoItem):
            self.actionDelete.setEnabled(True)
            self.actionManageRemotes.setEnabled(True)
            self.actionPush.setEnabled(True)
            self.actionPull.setEnabled(True)
        else:
            self.actionDelete.setEnabled(True)

    def openHelp(self):
        webbrowser.open('file://{}'.format(
            os.path.join(pluginPath, 'docs', 'html', 'index.html')))

    def manageRemotes(self):
        dlg = RemotesDialog(iface.mainWindow(), self.currentRepo)
        dlg.exec_()

    def pull(self):
        dlg = RemoteRefDialog(self.currentRepo)
        dlg.exec_()
        if dlg.remote is not None:
            conflicts = execute(
                lambda: self.currentRepo.pull(dlg.remote, dlg.branch))
            if conflicts:
                ret = QMessageBox.warning(
                    iface.mainWindow(), "Error while syncing",
                    "There are conflicts between local and remote changes.\n"
                    "Do you want to continue and fix them?",
                    QMessageBox.Yes | QMessageBox.No)
                if ret == QMessageBox.No:
                    self.currentRepo.closeTransaction(
                        conflicts[0].transactionId)
                    return

                dlg = ConflictDialog(conflicts)
                dlg.exec_()
                solved, resolvedConflicts = dlg.solved, dlg.resolvedConflicts
                if not solved:
                    self.repo.closeTransaction(conflicts[0].transactionId)
                    return
                for conflict, resolution in zip(
                        conflicts, list(resolvedConflicts.values())):
                    if resolution == ConflictDialog.LOCAL:
                        conflict.resolveWithLocalVersion()
                    elif resolution == ConflictDialog.REMOTE:
                        conflict.resolveWithRemoteVersion()
                    elif resolution == ConflictDialog.DELETE:
                        conflict.resolveDeletingFeature()
                    else:
                        conflict.resolveWithNewFeature(resolution)
                user, email = config.getUserInfo()
                if user is None:
                    return
                self.currentRepo.commitAndCloseMergeAndTransaction(
                    user, email, "Resolved merge conflicts",
                    conflicts[0].transactionId)
                config.iface.messageBar().pushMessage(
                    "Changes have been correctly pulled from remote",
                    level=QgsMessageBar.INFO,
                    duration=5)
                repoWatcher.repoChanged.emit(self.currentRepo)
            else:
                config.iface.messageBar().pushMessage(
                    "Changes have been correctly pulled from remote",
                    level=QgsMessageBar.INFO,
                    duration=5)
                repoWatcher.repoChanged.emit(self.currentRepo)

    def push(self):
        dlg = RemoteRefDialog(self.currentRepo)
        dlg.exec_()
        if dlg.remote is not None:
            try:
                self.currentRepo.push(dlg.remote, dlg.branch)
                config.iface.messageBar().pushMessage(
                    "Changes have been correctly pushed to remote",
                    level=QgsMessageBar.INFO,
                    duration=5)
            except CannotPushException:
                config.iface.messageBar().pushMessage(
                    "Changes could not be pushed to remote. Make sure you have pulled changed from the remote first.",
                    level=QgsMessageBar.WARNING,
                    duration=5)