Skip to content

Commit 7622424

Browse files
authored
Refactor divide plugin (#802)
* reverted to 1 file 744a8b0 * divided into data_item.py formated with black
1 parent e92686d commit 7622424

File tree

2 files changed

+66
-119
lines changed

2 files changed

+66
-119
lines changed

Mergin/data_item.py

Lines changed: 57 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# -*- coding: utf-8 -*-
2+
3+
# GPLv3 license
4+
# Copyright Lutra Consulting Limited
5+
16
from math import floor
27

38
try:
@@ -38,13 +43,11 @@
3843
mergin_project_local_path,
3944
PROJS_PER_PAGE,
4045
same_dir,
46+
get_local_mergin_projects_info,
4147
)
4248
from .utils_auth import AuthTokenExpiredError
4349
from .mergin.merginproject import MerginProject
4450

45-
MERGIN_CLIENT_LOG = os.path.join(QgsApplication.qgisSettingsDirPath(), "mergin-client-log.txt")
46-
os.environ["MERGIN_CLIENT_LOG"] = MERGIN_CLIENT_LOG
47-
4851

4952
class MerginRemoteProjectItem(QgsDataItem):
5053
"""Data item to represent a remote Mergin Maps project."""
@@ -56,16 +59,7 @@ def __init__(self, parent, project, project_manager, plugin):
5659
project["namespace"], project["name"]
5760
) # we need posix path for server API calls
5861
display_name = project["name"]
59-
group_items = project_manager.get_mergin_browser_groups()
60-
if group_items.get("Shared with me") == parent:
61-
display_name = self.project_name
62-
QgsDataItem.__init__(
63-
self,
64-
QgsDataItem.Collection,
65-
parent,
66-
display_name,
67-
"/Mergin/" + self.project_name,
68-
)
62+
QgsDataItem.__init__(self, QgsDataItem.Collection, parent, display_name, "/Mergin/" + self.project_name)
6963
self.path = None
7064
self.setSortKey(f"1 {self.name()}")
7165
self.setIcon(QIcon(icon_path("cloud.svg")))
@@ -103,10 +97,6 @@ def clone_remote_project(self):
10397
msg = "Mergin Maps project cloned successfully."
10498
QMessageBox.information(None, "Clone project", msg, QMessageBox.StandardButton.Close)
10599
self.parent().reload()
106-
# we also need to reload My projects group as the cloned project could appear there
107-
group_items = self.project_manager.get_mergin_browser_groups()
108-
if "My projects" in group_items:
109-
group_items["My projects"].reload()
110100

111101
def remove_remote_project(self):
112102
dlg = RemoveProjectDialog(self.project["namespace"], self.project["name"])
@@ -151,9 +141,6 @@ def __init__(self, parent, project, project_manager, plugin):
151141
self.project_name = posixpath.join(project["namespace"], project["name"]) # posix path for server API calls
152142
self.path = mergin_project_local_path(self.project_name)
153143
display_name = project["name"]
154-
group_items = project_manager.get_mergin_browser_groups()
155-
if group_items.get("Shared with me") == parent:
156-
display_name = self.project_name
157144
QgsDirectoryItem.__init__(self, parent, display_name, self.path, "/Mergin/" + self.project_name)
158145
self.setSortKey(f"0 {self.name()}")
159146
self.project = project
@@ -224,7 +211,7 @@ def remove_local_project(self):
224211
# as releasing lock on previously open files takes some time
225212
# we have to wait a bit before removing them, otherwise rmtree
226213
# will fail and removal of the local rpoject will fail as well
227-
QTimer.singleShot(250, lambda: shutil.rmtree(self.path))
214+
QTimer.singleShot(500, lambda: shutil.rmtree(self.path))
228215
except PermissionError as e:
229216
QgsApplication.messageLog().logMessage(f"Mergin Maps plugin: {str(e)}")
230217
msg = (
@@ -359,6 +346,7 @@ def __init__(
359346
self.error = ""
360347
self.wizard = None
361348
self.projects = []
349+
self.local_projects = []
362350
self.total_projects_count = None
363351
self.fetch_more_item = None
364352
self.create_new_project_item = None
@@ -372,16 +360,16 @@ def update_client_and_manager(self, mc=None, manager=None, err=None):
372360
self.project_manager = manager
373361
self.error = err
374362
self.projects = []
363+
self.local_projects = []
375364
self.updateName()
376365
self.depopulate()
377366

378367
def updateName(self):
379368
name = self.base_name
380369
try:
381-
if self.mc.server_type() != ServerType.OLD and self.plugin.current_workspace.get("name", None):
382-
name = f"{self.base_name} [{self.plugin.current_workspace['name']}]"
383-
except AttributeError:
384-
# self.mc might not be set yet
370+
name = f"{self.base_name} [{self.plugin.current_workspace['name']}]"
371+
except KeyError:
372+
# self.mc might not be set yet or there is no workspace
385373
pass
386374
self.setName(name)
387375

@@ -396,84 +384,74 @@ def createChildren(self):
396384
sip.transferto(error_item, self)
397385
return [error_item]
398386

399-
if self.mc.server_type() == ServerType.OLD:
400-
return self.createChildrenGroups()
401-
402387
return self.createChildrenProjects()
403388

404389
def createChildrenProjects(self):
405390
if not self.projects:
406391
error = self.fetch_projects()
407392
if error is not None:
408393
return error
394+
if not self.local_projects:
395+
self.local_projects = [
396+
{"namespace": i[1], "name": i[2]}
397+
for i in get_local_mergin_projects_info(self.plugin.current_workspace["name"])
398+
]
409399
items = []
410-
for project in self.projects:
411-
project_name = posixpath.join(project["namespace"], project["name"]) # posix path for server API calls
412-
local_proj_path = mergin_project_local_path(project_name)
413-
if local_proj_path is None or not os.path.exists(local_proj_path):
414-
item = MerginRemoteProjectItem(self, project, self.project_manager, self.plugin)
415-
item.setState(QgsDataItem.Populated) # make it non-expandable
416-
else:
417-
item = MerginLocalProjectItem(self, project, self.project_manager, self.plugin)
400+
401+
# build a set of (namespace, name) tuples for quick lookup
402+
local_keys = {(p["namespace"], p["name"]) for p in self.local_projects}
403+
# projects not present locally
404+
remote_only = [p for p in self.projects if (p["namespace"], p["name"]) not in local_keys]
405+
406+
for project in self.local_projects:
407+
item = MerginLocalProjectItem(self, project, self.project_manager, self.plugin)
408+
sip.transferto(item, self)
409+
items.append(item)
410+
411+
for project in remote_only:
412+
item = MerginRemoteProjectItem(self, project, self.project_manager, self.plugin)
413+
item.setState(QgsDataItem.Populated) # make it non-expandable
418414
sip.transferto(item, self)
419415
items.append(item)
420416
self.set_fetch_more_item()
421417
if self.fetch_more_item is not None:
422418
items.append(self.fetch_more_item)
423-
if not items and self.mc.server_type() != ServerType.OLD:
419+
if not items:
424420
self.create_new_project_item = CreateNewProjectItem(self)
425421
self.create_new_project_item.setState(QgsDataItem.Populated)
426422
sip.transferto(self.create_new_project_item, self)
427423
items.append(self.create_new_project_item)
428424
return items
429425

430-
def createChildrenGroups(self):
431-
items = []
432-
my_projects = MerginGroupItem(self, "My projects", "created", "user.svg", 1, self.plugin)
433-
my_projects.setState(QgsDataItem.Populated)
434-
my_projects.refresh()
435-
sip.transferto(my_projects, self)
436-
items.append(my_projects)
437-
438-
shared_projects = MerginGroupItem(self, "Shared with me", "shared", "users.svg", 2, self.plugin)
439-
shared_projects.setState(QgsDataItem.Populated)
440-
shared_projects.refresh()
441-
sip.transferto(shared_projects, self)
442-
items.append(shared_projects)
443-
444-
return items
445-
446426
def fetch_projects(self, page=1, per_page=PROJS_PER_PAGE):
447427
"""Get paginated projects list from Mergin Maps service. If anything goes wrong, return an error item."""
448428
if self.project_manager is None:
449-
error_item = QgsErrorItem(
450-
self,
451-
"Failed to log in. Please check the configuration",
452-
"/Mergin/error",
453-
)
429+
error_item = QgsErrorItem(self, "Failed to log in. Please check the configuration", "/Mergin/error")
454430
sip.transferto(error_item, self)
455431
return [error_item]
456-
if self.mc.server_type() != ServerType.OLD and not self.plugin.current_workspace:
432+
if not self.plugin.current_workspace:
457433
error_item = QgsErrorItem(self, "No workspace available", "/Mergin/error")
458434
sip.transferto(error_item, self)
459435
return [error_item]
460436
try:
461-
if self.mc.server_type() == ServerType.OLD:
462-
resp = self.project_manager.mc.paginated_projects_list(
463-
flag=self.filter,
464-
page=page,
465-
per_page=per_page,
466-
order_params="namespace_asc,name_asc",
467-
)
468-
else:
469-
resp = self.project_manager.mc.paginated_projects_list(
470-
only_namespace=self.plugin.current_workspace.get("name", None),
471-
page=page,
472-
per_page=per_page,
473-
order_params="name_asc",
474-
)
437+
resp = self.project_manager.mc.paginated_projects_list(
438+
only_namespace=self.plugin.current_workspace.get("name", None),
439+
page=page,
440+
per_page=per_page,
441+
order_params="name_asc",
442+
)
475443
self.projects += resp["projects"]
476444
self.total_projects_count = int(resp["count"]) if is_number(resp["count"]) else 0
445+
446+
# Sometimes we fetched a local, recursivly fetch until we fetched enougth at the same time
447+
set_fetched_projects = set([i["name"] for i in resp["projects"]])
448+
set_local_projects = set([i["name"] for i in self.local_projects])
449+
450+
new_projs_per_page_left = per_page - len(set_fetched_projects - set_local_projects)
451+
if new_projs_per_page_left != 0 and len(self.projects) < self.total_projects_count:
452+
new_page_to_get = floor(len(self.projects) / new_projs_per_page_left) + 1
453+
self.fetch_projects(new_page_to_get, per_page=new_projs_per_page_left)
454+
477455
except URLError:
478456
error_item = QgsErrorItem(self, "Failed to get projects from server", "/Mergin/error")
479457
sip.transferto(error_item, self)
@@ -497,16 +475,13 @@ def set_fetch_more_item(self):
497475
self.fetch_more_item = FetchMoreItem(self)
498476
self.fetch_more_item.setState(QgsDataItem.Populated)
499477
sip.transferto(self.fetch_more_item, self)
500-
if isinstance(self, MerginGroupItem):
501-
group_name = f"{self.base_name} ({self.total_projects_count})"
502-
self.setName(group_name)
503478

504479
def fetch_more(self):
505480
"""Fetch another page of projects and add them to the group item."""
506481
if self.fetch_more_item is None:
507482
QMessageBox.information(None, "Fetch Mergin Maps Projects", "All projects already listed.")
508483
return
509-
page_to_get = floor(self.rowCount() / PROJS_PER_PAGE) + 1
484+
page_to_get = floor(len(self.projects) / PROJS_PER_PAGE) + 1
510485
dummy = self.fetch_projects(page=page_to_get)
511486
self.refresh()
512487

@@ -515,6 +490,10 @@ def reload(self):
515490
self.plugin.choose_active_workspace()
516491

517492
self.projects = []
493+
self.local_projects = [
494+
{"namespace": i[1], "name": i[2]}
495+
for i in get_local_mergin_projects_info(self.plugin.current_workspace["name"])
496+
]
518497
self.refresh()
519498

520499
def new_project(self):
@@ -546,10 +525,7 @@ def actions(self, parent):
546525
actions = [action_configure]
547526
if self.mc:
548527
server_type = self.mc.server_type()
549-
if server_type == ServerType.OLD:
550-
actions.append(action_create)
551-
actions.append(action_explore)
552-
elif server_type == ServerType.CE:
528+
if server_type == ServerType.CE:
553529
actions.append(action_refresh)
554530
actions.append(action_create)
555531
actions.append(action_find)
@@ -563,33 +539,6 @@ def actions(self, parent):
563539
return actions
564540

565541

566-
class MerginGroupItem(MerginRootItem):
567-
"""Mergin group data item. Contains filtered list of Mergin Maps projects."""
568-
569-
def __init__(self, parent, grp_name, grp_filter, icon, order, plugin):
570-
MerginRootItem.__init__(self, parent, grp_name, grp_filter, icon, order, plugin)
571-
572-
def isMerginGroupItem(self):
573-
return True
574-
575-
def createChildren(self):
576-
return self.createChildrenProjects()
577-
578-
def actions(self, parent):
579-
action_refresh = QAction(QIcon(icon_path("repeat.svg")), "Reload", parent)
580-
action_refresh.triggered.connect(self.reload)
581-
actions = [action_refresh]
582-
if self.fetch_more_item is not None:
583-
action_fetch_more = QAction(QIcon(icon_path("dots.svg")), "Fetch more", parent)
584-
action_fetch_more.triggered.connect(self.fetch_more)
585-
actions.append(action_fetch_more)
586-
if self.name().startswith("My projects"):
587-
action_create = QAction(QIcon(icon_path("square-plus.svg")), "Create new project", parent)
588-
action_create.triggered.connect(self.new_project)
589-
actions.append(action_create)
590-
return actions
591-
592-
593542
class DataItemProvider(QgsDataItemProvider):
594543
def __init__(self, plugin):
595544
QgsDataItemProvider.__init__(self)

Mergin/plugin.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
# GPLv3 license
44
# Copyright Lutra Consulting Limited
5-
5+
try:
6+
import sip
7+
except ImportError:
8+
from PyQt6 import sip
69
import os
710
from functools import partial
811
from qgis.PyQt.QtCore import QUrl, QSettings, Qt
@@ -24,13 +27,13 @@
2427
ProjectSelectionDialog,
2528
PublicProjectSelectionDialog,
2629
)
30+
from .data_item import DataItemProvider
2731
from .create_project_wizard import NewMerginProjectWizard
2832
from .diff_dialog import DiffViewerDialog
2933
from .project_settings_widget import MerginProjectConfigFactory
3034
from .projects_manager import MerginProjectsManager
3135
from .configure_sync_wizard import DbSyncConfigWizard
3236
from .version_viewer_dialog import VersionViewerDialog
33-
from .data_item import DataItemProvider
3437
from .utils import (
3538
ServerType,
3639
ClientError,
@@ -53,6 +56,7 @@
5356
set_qgsexpressionscontext,
5457
get_authcfg,
5558
)
59+
5660
from .mergin.merginproject import MerginProject
5761
from .processing.provider import MerginProvider
5862
import processing
@@ -422,13 +426,9 @@ def choose_active_workspace(self):
422426
user_info = self.mc.user_info()
423427
workspaces = user_info.get("workspaces", None)
424428
if not workspaces:
425-
if workspaces is None:
426-
# server is old, does not support workspaces
427-
self.current_workspace = dict()
428-
else:
429-
# User has no workspaces
430-
self.show_no_workspaces_dialog()
431-
self.current_workspace = dict()
429+
# User has no workspaces
430+
self.show_no_workspaces_dialog()
431+
self.current_workspace = dict()
432432
return
433433

434434
if len(workspaces) == 1:
@@ -467,8 +467,6 @@ def create_new_project(self):
467467
return
468468

469469
default_workspace = self.current_workspace.get("name", None)
470-
if self.mc.server_type() == ServerType.OLD:
471-
default_workspace = user_info["username"]
472470

473471
wizard = NewMerginProjectWizard(self.manager, user_info=user_info, default_workspace=default_workspace)
474472
if not wizard.exec():

0 commit comments

Comments
 (0)