feat: add status bar gauge and implement pagination for site and folder fetching
This commit is contained in:
@@ -904,8 +904,14 @@ class SharePointApp(wx.Frame):
|
|||||||
self.refresh_fav_list()
|
self.refresh_fav_list()
|
||||||
|
|
||||||
# 4. STATUS BAR
|
# 4. STATUS BAR
|
||||||
self.status_bar = self.CreateStatusBar()
|
self.status_bar = self.CreateStatusBar(2)
|
||||||
self.status_bar.SetStatusText(self.get_txt("status_ready"))
|
self.status_bar.SetStatusWidths([-1, 150]) # Text field and Gauge field
|
||||||
|
self.status_bar.SetStatusText(self.get_txt("status_ready"), 0)
|
||||||
|
|
||||||
|
# Add a Gauge to the status bar
|
||||||
|
self.gauge = wx.Gauge(self.status_bar, range=100, size=(140, 18), style=wx.GA_HORIZONTAL | wx.GA_SMOOTH)
|
||||||
|
self.gauge.Hide()
|
||||||
|
self.Bind(wx.EVT_SIZE, self.on_status_bar_resize)
|
||||||
|
|
||||||
panel.SetSizer(vbox)
|
panel.SetSizer(vbox)
|
||||||
self.Bind(wx.EVT_SIZE, self.on_resize)
|
self.Bind(wx.EVT_SIZE, self.on_resize)
|
||||||
@@ -1315,21 +1321,39 @@ class SharePointApp(wx.Frame):
|
|||||||
os.makedirs(local_dir)
|
os.makedirs(local_dir)
|
||||||
|
|
||||||
url = f"https://graph.microsoft.com/v1.0/drives/{drive_id}/items/{folder_id}/children"
|
url = f"https://graph.microsoft.com/v1.0/drives/{drive_id}/items/{folder_id}/children"
|
||||||
res = requests.get(url, headers=self.headers)
|
while url:
|
||||||
if res.status_code == 200:
|
res = requests.get(url, headers=self.headers)
|
||||||
items = res.json().get('value', [])
|
if res.status_code == 200:
|
||||||
for item in items:
|
res_data = res.json()
|
||||||
item_path = os.path.join(local_dir, item['name'])
|
items = res_data.get('value', [])
|
||||||
if 'folder' in item:
|
for item in items:
|
||||||
self._download_folder_recursive_sync(drive_id, item['id'], item_path)
|
item_path = os.path.join(local_dir, item['name'])
|
||||||
else:
|
if 'folder' in item:
|
||||||
self._download_file_sync_call(drive_id, item['id'], item_path)
|
self._download_folder_recursive_sync(drive_id, item['id'], item_path)
|
||||||
|
else:
|
||||||
|
self._download_file_sync_call(drive_id, item['id'], item_path)
|
||||||
|
url = res_data.get('@odata.nextLink')
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
def set_status(self, text):
|
def set_status(self, text, field=0):
|
||||||
wx.CallAfter(self.status_bar.SetStatusText, text)
|
wx.CallAfter(self.status_bar.SetStatusText, text, field)
|
||||||
|
|
||||||
|
def pulse_gauge(self, start=True):
|
||||||
|
def _do():
|
||||||
|
if not self: return
|
||||||
|
if start:
|
||||||
|
self.gauge.Show()
|
||||||
|
self.gauge.Pulse()
|
||||||
|
else:
|
||||||
|
self.gauge.Hide()
|
||||||
|
self.gauge.SetValue(0)
|
||||||
|
self.Layout()
|
||||||
|
wx.CallAfter(_do)
|
||||||
|
|
||||||
def show_info(self, text, type=wx.ICON_INFORMATION, auto_hide=True):
|
def show_info(self, text, type=wx.ICON_INFORMATION, auto_hide=True):
|
||||||
def _do():
|
def _do():
|
||||||
|
if not self: return
|
||||||
self.info_bar.Dismiss()
|
self.info_bar.Dismiss()
|
||||||
self.info_bar.ShowMessage(text, type)
|
self.info_bar.ShowMessage(text, type)
|
||||||
if auto_hide:
|
if auto_hide:
|
||||||
@@ -1504,6 +1528,13 @@ class SharePointApp(wx.Frame):
|
|||||||
|
|
||||||
event.Skip()
|
event.Skip()
|
||||||
|
|
||||||
|
def on_status_bar_resize(self, event):
|
||||||
|
if hasattr(self, 'gauge') and self.gauge:
|
||||||
|
rect = self.status_bar.GetFieldRect(1)
|
||||||
|
self.gauge.SetPosition((rect.x + 5, rect.y + 2))
|
||||||
|
self.gauge.SetSize((rect.width - 10, rect.height - 4))
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
def _update_button_labels(self, full=True):
|
def _update_button_labels(self, full=True):
|
||||||
if not self: return
|
if not self: return
|
||||||
try:
|
try:
|
||||||
@@ -1629,7 +1660,6 @@ class SharePointApp(wx.Frame):
|
|||||||
self.access_token = result["access_token"]
|
self.access_token = result["access_token"]
|
||||||
self.headers = {'Authorization': f'Bearer {self.access_token}'}
|
self.headers = {'Authorization': f'Bearer {self.access_token}'}
|
||||||
self.login_btn.Disable()
|
self.login_btn.Disable()
|
||||||
# self.login_btn.Hide() # Valgfrit: Skjul login knap helt når vi er inde
|
|
||||||
self.login_btn.SetLabel(self.get_txt("btn_logged_in") if not getattr(self, "compact_mode", False) else "")
|
self.login_btn.SetLabel(self.get_txt("btn_logged_in") if not getattr(self, "compact_mode", False) else "")
|
||||||
self.login_btn.SetBackgroundColour(wx.Colour(200, 200, 200)) # Grå
|
self.login_btn.SetBackgroundColour(wx.Colour(200, 200, 200)) # Grå
|
||||||
self.home_btn.Enable()
|
self.home_btn.Enable()
|
||||||
@@ -1657,14 +1687,27 @@ class SharePointApp(wx.Frame):
|
|||||||
|
|
||||||
def _fetch_sites_bg(self):
|
def _fetch_sites_bg(self):
|
||||||
if not self.ensure_valid_token(): return
|
if not self.ensure_valid_token(): return
|
||||||
|
self.pulse_gauge(True)
|
||||||
|
all_sites = []
|
||||||
url = "https://graph.microsoft.com/v1.0/sites?search=*"
|
url = "https://graph.microsoft.com/v1.0/sites?search=*"
|
||||||
res = requests.get(url, headers=self.headers)
|
|
||||||
if res.status_code == 200:
|
while url:
|
||||||
sites = res.json().get('value', [])
|
res = requests.get(url, headers=self.headers)
|
||||||
sites.sort(key=lambda x: x.get('displayName', x.get('name', '')).lower())
|
if res.status_code == 200:
|
||||||
wx.CallAfter(self._populate_sites_tree, sites)
|
data = res.json()
|
||||||
|
all_sites.extend(data.get('value', []))
|
||||||
|
url = data.get('@odata.nextLink')
|
||||||
|
self.set_status(f"{self.get_txt('status_fetching_sites')} ({len(all_sites)}...)")
|
||||||
|
self.pulse_gauge(True)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if all_sites:
|
||||||
|
all_sites.sort(key=lambda x: x.get('displayName', x.get('name', '')).lower())
|
||||||
|
wx.CallAfter(self._populate_sites_tree, all_sites)
|
||||||
else:
|
else:
|
||||||
self.set_status(self.get_txt("msg_unknown_error"))
|
self.set_status(self.get_txt("msg_unknown_error"))
|
||||||
|
self.pulse_gauge(False)
|
||||||
|
|
||||||
def _populate_sites_tree(self, sites):
|
def _populate_sites_tree(self, sites):
|
||||||
self.set_status(f"{len(sites)} sites.")
|
self.set_status(f"{len(sites)} sites.")
|
||||||
@@ -1678,102 +1721,15 @@ class SharePointApp(wx.Frame):
|
|||||||
}
|
}
|
||||||
self.tree_ctrl.SetItemHasChildren(node, True)
|
self.tree_ctrl.SetItemHasChildren(node, True)
|
||||||
|
|
||||||
# Select the first site or just show in list (defaulting to showing root sites in list)
|
# Root sites in list view
|
||||||
self.list_ctrl.DeleteAllItems()
|
self.list_ctrl.DeleteAllItems()
|
||||||
self.current_items = []
|
self.current_items = []
|
||||||
for i, site in enumerate(sites):
|
for i, site in enumerate(sites):
|
||||||
name = site.get('displayName', site.get('name'))
|
name = site.get('displayName', site.get('name'))
|
||||||
self.list_ctrl.InsertItem(i, name, self.idx_site)
|
self.list_ctrl.InsertItem(i, name, self.idx_site)
|
||||||
self.list_ctrl.SetItem(i, 1, self.get_txt("type_site"))
|
self.list_ctrl.SetItem(i, 1, self.get_txt("type_site"))
|
||||||
self.list_ctrl.SetItem(i, 2, "") # Størrelse
|
self.list_ctrl.SetItem(i, 2, "")
|
||||||
self.list_ctrl.SetItem(i, 3, "") # Sidst ændret
|
self.list_ctrl.SetItem(i, 3, "")
|
||||||
self.current_items.append({
|
|
||||||
"type": "SITE", "id": site['id'], "name": name,
|
|
||||||
"size": None, "modified": "", "web_url": site.get('webUrl')
|
|
||||||
})
|
|
||||||
|
|
||||||
def on_tree_expanding(self, event):
|
|
||||||
item = event.GetItem()
|
|
||||||
data = self.tree_item_data.get(item)
|
|
||||||
if not data or data.get("loaded"):
|
|
||||||
return
|
|
||||||
|
|
||||||
loading_node = self.tree_ctrl.AppendItem(item, self.get_txt("status_loading"))
|
|
||||||
threading.Thread(target=self._fetch_tree_children_bg, args=(item, data), daemon=True).start()
|
|
||||||
|
|
||||||
def _fetch_tree_children_bg(self, parent_node, data):
|
|
||||||
if not self.ensure_valid_token(): return
|
|
||||||
if data['type'] == "SITE":
|
|
||||||
url = f"https://graph.microsoft.com/v1.0/sites/{data['id']}/drives"
|
|
||||||
res = requests.get(url, headers=self.headers)
|
|
||||||
if res.status_code == 200:
|
|
||||||
drives = res.json().get('value', [])
|
|
||||||
drives.sort(key=lambda x: x.get('name', '').lower())
|
|
||||||
wx.CallAfter(self._populate_tree_drives, parent_node, drives, data)
|
|
||||||
elif data['type'] == "DRIVE":
|
|
||||||
url = f"https://graph.microsoft.com/v1.0/drives/{data['id']}/root/children"
|
|
||||||
res = requests.get(url, headers=self.headers)
|
|
||||||
if res.status_code == 200:
|
|
||||||
items = res.json().get('value', [])
|
|
||||||
folders = [x for x in items if 'folder' in x]
|
|
||||||
folders.sort(key=lambda x: x['name'].lower())
|
|
||||||
wx.CallAfter(self._populate_tree_folders, parent_node, folders, data)
|
|
||||||
elif data['type'] == "FOLDER":
|
|
||||||
url = f"https://graph.microsoft.com/v1.0/drives/{data['drive_id']}/items/{data['id']}/children"
|
|
||||||
res = requests.get(url, headers=self.headers)
|
|
||||||
if res.status_code == 200:
|
|
||||||
items = res.json().get('value', [])
|
|
||||||
folders = [x for x in items if 'folder' in x]
|
|
||||||
folders.sort(key=lambda x: x['name'].lower())
|
|
||||||
wx.CallAfter(self._populate_tree_folders, parent_node, folders, data)
|
|
||||||
|
|
||||||
def load_sites(self, event=None):
|
|
||||||
self.set_status(self.get_txt("status_fetching_sites"))
|
|
||||||
self.tree_ctrl.DeleteAllItems()
|
|
||||||
self.list_ctrl.DeleteAllItems()
|
|
||||||
self.current_items = []
|
|
||||||
self.tree_item_data = {}
|
|
||||||
self._pending_tree_selection_id = None
|
|
||||||
|
|
||||||
self.tree_root = self.tree_ctrl.AddRoot("HiddenRoot")
|
|
||||||
self.current_path = ["SharePoint"]
|
|
||||||
self.history = []
|
|
||||||
self.update_path_display()
|
|
||||||
|
|
||||||
threading.Thread(target=self._fetch_sites_bg, daemon=True).start()
|
|
||||||
|
|
||||||
def _fetch_sites_bg(self):
|
|
||||||
if not self.ensure_valid_token(): return
|
|
||||||
url = "https://graph.microsoft.com/v1.0/sites?search=*"
|
|
||||||
res = requests.get(url, headers=self.headers)
|
|
||||||
if res.status_code == 200:
|
|
||||||
sites = res.json().get('value', [])
|
|
||||||
sites.sort(key=lambda x: x.get('displayName', x.get('name', '')).lower())
|
|
||||||
wx.CallAfter(self._populate_sites_tree, sites)
|
|
||||||
else:
|
|
||||||
self.set_status(self.get_txt("msg_unknown_error"))
|
|
||||||
|
|
||||||
def _populate_sites_tree(self, sites):
|
|
||||||
self.set_status(f"{len(sites)} sites.")
|
|
||||||
for site in sites:
|
|
||||||
name = site.get('displayName', site.get('name'))
|
|
||||||
node = self.tree_ctrl.AppendItem(self.tree_root, name, image=self.idx_site)
|
|
||||||
self.tree_item_data[node] = {
|
|
||||||
"type": "SITE", "id": site['id'], "name": name,
|
|
||||||
"drive_id": None, "path": ["SharePoint", name], "loaded": False,
|
|
||||||
"web_url": site.get('webUrl')
|
|
||||||
}
|
|
||||||
self.tree_ctrl.SetItemHasChildren(node, True)
|
|
||||||
|
|
||||||
# Select the first site or just show in list (defaulting to showing root sites in list)
|
|
||||||
self.list_ctrl.DeleteAllItems()
|
|
||||||
self.current_items = []
|
|
||||||
for i, site in enumerate(sites):
|
|
||||||
name = site.get('displayName', site.get('name'))
|
|
||||||
self.list_ctrl.InsertItem(i, name, self.idx_site)
|
|
||||||
self.list_ctrl.SetItem(i, 1, self.get_txt("type_site"))
|
|
||||||
self.list_ctrl.SetItem(i, 2, "") # Størrelse
|
|
||||||
self.list_ctrl.SetItem(i, 3, "") # Sidst ændret
|
|
||||||
self.current_items.append({
|
self.current_items.append({
|
||||||
"type": "SITE", "id": site['id'], "name": name,
|
"type": "SITE", "id": site['id'], "name": name,
|
||||||
"size": None, "modified": "", "web_url": site.get('webUrl'),
|
"size": None, "modified": "", "web_url": site.get('webUrl'),
|
||||||
@@ -1791,29 +1747,34 @@ class SharePointApp(wx.Frame):
|
|||||||
|
|
||||||
def _fetch_tree_children_bg(self, parent_node, data):
|
def _fetch_tree_children_bg(self, parent_node, data):
|
||||||
if not self.ensure_valid_token(): return
|
if not self.ensure_valid_token(): return
|
||||||
|
self.pulse_gauge(True)
|
||||||
|
all_children = []
|
||||||
|
|
||||||
if data['type'] == "SITE":
|
if data['type'] == "SITE":
|
||||||
url = f"https://graph.microsoft.com/v1.0/sites/{data['id']}/drives"
|
url = f"https://graph.microsoft.com/v1.0/sites/{data['id']}/drives"
|
||||||
res = requests.get(url, headers=self.headers)
|
|
||||||
if res.status_code == 200:
|
|
||||||
drives = res.json().get('value', [])
|
|
||||||
drives.sort(key=lambda x: x.get('name', '').lower())
|
|
||||||
wx.CallAfter(self._populate_tree_drives, parent_node, drives, data)
|
|
||||||
elif data['type'] == "DRIVE":
|
elif data['type'] == "DRIVE":
|
||||||
url = f"https://graph.microsoft.com/v1.0/drives/{data['id']}/root/children"
|
url = f"https://graph.microsoft.com/v1.0/drives/{data['id']}/root/children"
|
||||||
res = requests.get(url, headers=self.headers)
|
|
||||||
if res.status_code == 200:
|
|
||||||
items = res.json().get('value', [])
|
|
||||||
folders = [x for x in items if 'folder' in x]
|
|
||||||
folders.sort(key=lambda x: x['name'].lower())
|
|
||||||
wx.CallAfter(self._populate_tree_folders, parent_node, folders, data)
|
|
||||||
elif data['type'] == "FOLDER":
|
elif data['type'] == "FOLDER":
|
||||||
url = f"https://graph.microsoft.com/v1.0/drives/{data['drive_id']}/items/{data['id']}/children"
|
url = f"https://graph.microsoft.com/v1.0/drives/{data['drive_id']}/items/{data['id']}/children"
|
||||||
|
|
||||||
|
while url:
|
||||||
res = requests.get(url, headers=self.headers)
|
res = requests.get(url, headers=self.headers)
|
||||||
if res.status_code == 200:
|
if res.status_code == 200:
|
||||||
items = res.json().get('value', [])
|
res_data = res.json()
|
||||||
folders = [x for x in items if 'folder' in x]
|
all_children.extend(res_data.get('value', []))
|
||||||
folders.sort(key=lambda x: x['name'].lower())
|
url = res_data.get('@odata.nextLink')
|
||||||
wx.CallAfter(self._populate_tree_folders, parent_node, folders, data)
|
self.pulse_gauge(True)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if data['type'] == "SITE":
|
||||||
|
all_children.sort(key=lambda x: x.get('name', '').lower())
|
||||||
|
wx.CallAfter(self._populate_tree_drives, parent_node, all_children, data)
|
||||||
|
else:
|
||||||
|
folders = [x for x in all_children if 'folder' in x]
|
||||||
|
folders.sort(key=lambda x: x['name'].lower())
|
||||||
|
wx.CallAfter(self._populate_tree_folders, parent_node, folders, data)
|
||||||
|
self.pulse_gauge(False)
|
||||||
|
|
||||||
def _populate_tree_drives(self, parent_node, drives, parent_data):
|
def _populate_tree_drives(self, parent_node, drives, parent_data):
|
||||||
self.tree_ctrl.DeleteChildren(parent_node)
|
self.tree_ctrl.DeleteChildren(parent_node)
|
||||||
@@ -1907,36 +1868,40 @@ class SharePointApp(wx.Frame):
|
|||||||
|
|
||||||
def _fetch_list_contents_bg(self, data):
|
def _fetch_list_contents_bg(self, data):
|
||||||
if not self.ensure_valid_token(): return
|
if not self.ensure_valid_token(): return
|
||||||
|
self.pulse_gauge(True)
|
||||||
items_data = []
|
items_data = []
|
||||||
|
|
||||||
if data['type'] == "SITE":
|
if data['type'] == "SITE":
|
||||||
url = f"https://graph.microsoft.com/v1.0/sites/{data['id']}/drives"
|
url = f"https://graph.microsoft.com/v1.0/sites/{data['id']}/drives"
|
||||||
|
elif data['type'] == "DRIVE":
|
||||||
|
url = f"https://graph.microsoft.com/v1.0/drives/{data['id']}/root/children"
|
||||||
|
else: # FOLDER
|
||||||
|
url = f"https://graph.microsoft.com/v1.0/drives/{data['drive_id']}/items/{data['id']}/children"
|
||||||
|
|
||||||
|
first_chunk = True
|
||||||
|
while url:
|
||||||
res = requests.get(url, headers=self.headers)
|
res = requests.get(url, headers=self.headers)
|
||||||
if res.status_code == 200:
|
if res.status_code != 200: break
|
||||||
drives = res.json().get('value', [])
|
|
||||||
drives.sort(key=lambda x: x.get('name', '').lower())
|
res_data = res.json()
|
||||||
for drive in drives:
|
raw_items = res_data.get('value', [])
|
||||||
name = drive.get('name', '')
|
|
||||||
items_data.append({
|
# Map items
|
||||||
"type": "DRIVE", "id": drive['id'], "name": name,
|
chunk_data = []
|
||||||
"drive_id": drive['id'], "modified": "", "size": None,
|
drive_id = data.get('drive_id') if data['type'] != "SITE" else None
|
||||||
"web_url": drive.get('webUrl'),
|
for item in raw_items:
|
||||||
|
if data['type'] == "SITE":
|
||||||
|
name = item.get('name', '')
|
||||||
|
chunk_data.append({
|
||||||
|
"type": "DRIVE", "id": item['id'], "name": name,
|
||||||
|
"drive_id": item['id'], "modified": "", "size": None,
|
||||||
|
"web_url": item.get('webUrl'),
|
||||||
"path": data['path'] + [name]
|
"path": data['path'] + [name]
|
||||||
})
|
})
|
||||||
elif data['type'] in ["DRIVE", "FOLDER"]:
|
else:
|
||||||
drive_id = data['drive_id']
|
|
||||||
if data['type'] == "DRIVE":
|
|
||||||
url = f"https://graph.microsoft.com/v1.0/drives/{drive_id}/root/children"
|
|
||||||
else:
|
|
||||||
url = f"https://graph.microsoft.com/v1.0/drives/{drive_id}/items/{data['id']}/children"
|
|
||||||
|
|
||||||
res = requests.get(url, headers=self.headers)
|
|
||||||
if res.status_code == 200:
|
|
||||||
items = res.json().get('value', [])
|
|
||||||
items.sort(key=lambda x: (not 'folder' in x, x['name'].lower()))
|
|
||||||
for item in items:
|
|
||||||
is_folder = 'folder' in item
|
is_folder = 'folder' in item
|
||||||
modified = item.get('lastModifiedDateTime', '').replace('T', ' ').split('.')[0]
|
modified = item.get('lastModifiedDateTime', '').replace('T', ' ').split('.')[0]
|
||||||
items_data.append({
|
chunk_data.append({
|
||||||
"type": "FOLDER" if is_folder else "FILE",
|
"type": "FOLDER" if is_folder else "FILE",
|
||||||
"id": item['id'], "name": item['name'],
|
"id": item['id'], "name": item['name'],
|
||||||
"drive_id": drive_id, "modified": modified,
|
"drive_id": drive_id, "modified": modified,
|
||||||
@@ -1945,8 +1910,50 @@ class SharePointApp(wx.Frame):
|
|||||||
"hash": item.get('file', {}).get('hashes', {}).get('quickXorHash') if not is_folder else None,
|
"hash": item.get('file', {}).get('hashes', {}).get('quickXorHash') if not is_folder else None,
|
||||||
"path": data['path'] + [item['name']]
|
"path": data['path'] + [item['name']]
|
||||||
})
|
})
|
||||||
|
|
||||||
wx.CallAfter(self._populate_list_ctrl, items_data, data)
|
items_data.extend(chunk_data)
|
||||||
|
self.set_status(f"Henter... ({len(items_data)} emner)")
|
||||||
|
self.pulse_gauge(True)
|
||||||
|
|
||||||
|
# Chunked UI Update
|
||||||
|
if first_chunk:
|
||||||
|
wx.CallAfter(self._populate_list_ctrl, chunk_data, data, finalize=False)
|
||||||
|
first_chunk = False
|
||||||
|
else:
|
||||||
|
wx.CallAfter(self._append_list_items, chunk_data)
|
||||||
|
|
||||||
|
url = res_data.get('@odata.nextLink')
|
||||||
|
|
||||||
|
# Finalize
|
||||||
|
wx.CallAfter(self._finalize_list_loading, items_data)
|
||||||
|
self.pulse_gauge(False)
|
||||||
|
|
||||||
|
def _append_list_items(self, items):
|
||||||
|
if not self: return
|
||||||
|
start_idx = len(self.current_items)
|
||||||
|
self.current_items.extend(items)
|
||||||
|
|
||||||
|
for i, item in enumerate(items):
|
||||||
|
idx = start_idx + i
|
||||||
|
img_idx = self.idx_file
|
||||||
|
if item['type'] == "FOLDER": img_idx = self.idx_folder
|
||||||
|
elif item['type'] == "DRIVE": img_idx = self.idx_drive
|
||||||
|
elif item['type'] == "SITE": img_idx = self.idx_site
|
||||||
|
elif item['type'] == "FILE":
|
||||||
|
img_idx = self.get_icon_idx_for_file(item['name'])
|
||||||
|
|
||||||
|
self.list_ctrl.InsertItem(idx, item['name'], img_idx)
|
||||||
|
type_str = self.get_txt("type_folder") if item['type'] == "FOLDER" else self.get_txt("type_file") if item['type'] == "FILE" else self.get_txt("type_drive")
|
||||||
|
self.list_ctrl.SetItem(idx, 1, type_str)
|
||||||
|
size_str = format_size(item['size']) if item['size'] is not None else ""
|
||||||
|
self.list_ctrl.SetItem(idx, 2, size_str)
|
||||||
|
self.list_ctrl.SetItem(idx, 3, item['modified'])
|
||||||
|
|
||||||
|
def _finalize_list_loading(self, items_data):
|
||||||
|
if not self: return
|
||||||
|
self.current_items = items_data
|
||||||
|
self.apply_sorting()
|
||||||
|
self.set_status(self.get_txt("status_ready"))
|
||||||
|
|
||||||
def on_column_click(self, event):
|
def on_column_click(self, event):
|
||||||
col = event.GetColumn()
|
col = event.GetColumn()
|
||||||
@@ -2076,30 +2083,37 @@ class SharePointApp(wx.Frame):
|
|||||||
info.SetImage(-1)
|
info.SetImage(-1)
|
||||||
self.list_ctrl.SetColumn(col, info)
|
self.list_ctrl.SetColumn(col, info)
|
||||||
|
|
||||||
def _populate_list_ctrl(self, items_data, parent_data):
|
def _populate_list_ctrl(self, items_data, parent_data, finalize=True):
|
||||||
if not self: return
|
if not self: return
|
||||||
try:
|
try:
|
||||||
self.current_items = items_data
|
self.current_items = items_data
|
||||||
|
|
||||||
# Anvend sortering før visning
|
if finalize:
|
||||||
self.apply_sorting()
|
# Anvend sortering før visning
|
||||||
|
self.apply_sorting()
|
||||||
|
else:
|
||||||
|
# Bare vis de nuværende usorteret (for hurtigere feedback)
|
||||||
|
self._update_list_view_only()
|
||||||
|
|
||||||
# Opdater tilstand
|
# Opdater tilstand (kun første gang)
|
||||||
self.current_web_url = parent_data.get('web_url')
|
if parent_data:
|
||||||
|
self.current_web_url = parent_data.get('web_url')
|
||||||
if parent_data['type'] == "SITE":
|
|
||||||
self.current_site_id = parent_data['id']
|
|
||||||
elif parent_data['type'] == "DRIVE":
|
|
||||||
self.current_drive_id = parent_data['id']
|
|
||||||
self.current_folder_id = "root"
|
|
||||||
elif parent_data['type'] == "FOLDER":
|
|
||||||
self.current_drive_id = parent_data['drive_id']
|
|
||||||
self.current_folder_id = parent_data['id']
|
|
||||||
|
|
||||||
# Opdater knap-synlighed
|
if parent_data['type'] == "SITE":
|
||||||
can_upload = self.current_drive_id is not None
|
self.current_site_id = parent_data['id']
|
||||||
wx.CallAfter(lambda: self._safe_update_buttons(can_upload))
|
elif parent_data['type'] == "DRIVE":
|
||||||
self.set_status(self.get_txt("status_ready"))
|
self.current_drive_id = parent_data['id']
|
||||||
|
self.current_folder_id = "root"
|
||||||
|
elif parent_data['type'] == "FOLDER":
|
||||||
|
self.current_drive_id = parent_data['drive_id']
|
||||||
|
self.current_folder_id = parent_data['id']
|
||||||
|
|
||||||
|
# Opdater knap-synlighed
|
||||||
|
can_upload = self.current_drive_id is not None
|
||||||
|
wx.CallAfter(lambda: self._safe_update_buttons(can_upload))
|
||||||
|
|
||||||
|
if finalize:
|
||||||
|
self.set_status(self.get_txt("status_ready"))
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user