88from PySide6 .QtWidgets import (QApplication , QMainWindow , QWidget , QVBoxLayout ,
99 QHBoxLayout , QListWidget , QListWidgetItem ,
1010 QPushButton , QLineEdit , QSplitter ,
11- QListView , QMenu )
11+ QListView , QMenu , QProgressDialog )
1212from PySide6 .QtCore import Qt , QSize
1313from PySide6 .QtGui import QIcon , QPixmap , QShortcut , QKeySequence
1414
1515import pytablericons
1616from pytablericons .outline_icon import OutlineIcon
1717from pytablericons .filled_icon import FilledIcon
1818
19- from gdrive import gcache
2019
2120from PySide6 .QtSvg import QSvgRenderer
22- from PySide6 .QtCore import QByteArray , Qt , QRunnable , Signal , QThreadPool , Slot , QTimer
21+ from PySide6 .QtCore import QByteArray , Qt , QRunnable , Signal , QThreadPool , Slot , QTimer , QThread
2322from PySide6 .QtGui import QPainter , QImage
2423
2524from collections import OrderedDict
3029from strutils import thumbnail_path_for_file , THUMBNAIL_SIZES
3130
3231
32+ class GCacheLoaderThread (QThread ):
33+ progress_text_changed = Signal (str )
34+ progress_value_changed = Signal (int , int ) # current, total
35+
36+ def run (self ):
37+ import local_gdrive
38+ import gdrive_base
39+
40+ original_yaspin = getattr (local_gdrive , 'yaspin' , None )
41+ original_trange = getattr (gdrive_base , 'trange' , None )
42+
43+ class MockYaspin :
44+ def __init__ (self_mock , * args , ** kwargs ):
45+ self_mock .text = kwargs .get ('text' , args [0 ] if args else "" )
46+ def __enter__ (self_mock ):
47+ self .progress_text_changed .emit (self_mock .text )
48+ self .progress_value_changed .emit (0 , 0 )
49+ return self_mock
50+ def __exit__ (self_mock , exc_type , exc_val , exc_tb ):
51+ pass
52+ def write (self_mock , text ):
53+ pass
54+
55+ def mock_trange (* args , ** kwargs ):
56+ r = range (* args )
57+ total = len (r )
58+ self .progress_value_changed .emit (0 , total )
59+ for i , val in enumerate (r ):
60+ self .progress_value_changed .emit (i , total )
61+ yield val
62+ self .progress_value_changed .emit (total , total )
63+
64+ local_gdrive .yaspin = MockYaspin
65+ gdrive_base .trange = mock_trange
66+
67+ try :
68+ import gdrive
69+ finally :
70+ if original_yaspin :
71+ local_gdrive .yaspin = original_yaspin
72+ if original_trange :
73+ gdrive_base .trange = original_trange
74+
75+
3376class ThumbnailWorker (QRunnable ):
3477 def __init__ (self , item , cancel_flag , emit_callback ):
3578 super ().__init__ ()
@@ -144,7 +187,7 @@ def get_mime_icon(mime_type: str) -> QIcon:
144187 elif mime_type == 'application/vnd.google-apps.shortcut+file' :
145188 return get_icon (OutlineIcon .FILE_SYMLINK , color = "#999999" )
146189 elif mime_type == 'application/vnd.google-apps.shortcut+folder' :
147- return get_icon (OutlineIcon .FOLDER_SYMLINK , color = "#999999" )
190+ return get_icon (OutlineIcon .FOLDER_SYMLINK , color = color )
148191 elif mime_type == 'application/vnd.google-apps.document' :
149192 return get_icon (OutlineIcon .FILE_TEXT , color = "#4285F4" )
150193 elif mime_type == 'application/vnd.google-apps.spreadsheet' :
@@ -192,7 +235,30 @@ def __init__(self):
192235 self .queued_thumbnails = set ()
193236 self .thumbnail_loaded_signal .connect (self .on_thumbnail_loaded )
194237
238+ self .gcache = None
195239 self .init_ui ()
240+
241+ self .progress_dialog = QProgressDialog ("Loading GDrive Cache..." , "Cancel" , 0 , 0 , self )
242+ self .progress_dialog .setWindowTitle ("Please Wait" )
243+ self .progress_dialog .setWindowModality (Qt .WindowModal )
244+ self .progress_dialog .setCancelButton (None )
245+ self .progress_dialog .setMinimumDuration (0 )
246+ self .progress_dialog .setValue (0 )
247+
248+ self .loader_thread = GCacheLoaderThread (self )
249+ self .loader_thread .progress_text_changed .connect (self .progress_dialog .setLabelText )
250+ self .loader_thread .progress_value_changed .connect (self .update_progress )
251+ self .loader_thread .finished .connect (self .on_gcache_loaded )
252+ self .loader_thread .start ()
253+
254+ def update_progress (self , current , total ):
255+ self .progress_dialog .setMaximum (total )
256+ self .progress_dialog .setValue (current )
257+
258+ def on_gcache_loaded (self ):
259+ self .progress_dialog .close ()
260+ import gdrive
261+ self .gcache = gdrive .gcache
196262 self .load_root ("my_drive" )
197263
198264 def init_ui (self ):
@@ -272,10 +338,12 @@ def init_ui(self):
272338
273339 self .file_view .setFocus ()
274340
275- def apply_icon_overlay (self , pixmap : QPixmap , icon_enum : Any , color : str = "#999999" , is_filled : bool = False ) -> QPixmap :
341+ def apply_icon_overlay (self , pixmap : QPixmap , icon_enum : Any , color : str = None , is_filled : bool = False ) -> QPixmap :
276342 result = QPixmap (pixmap )
277343 painter = QPainter (result )
278344 painter .setRenderHint (QPainter .Antialiasing )
345+ if not color :
346+ color = QApplication .palette ().text ().color ().name ()
279347
280348 overlay_icon = get_icon (icon_enum , color = color , is_filled = is_filled )
281349 overlay_size = pixmap .width () // 4
@@ -285,8 +353,9 @@ def apply_icon_overlay(self, pixmap: QPixmap, icon_enum: Any, color: str = "#999
285353 x = pixmap .width () - overlay_size - 4
286354 y = pixmap .height () - overlay_size - 4
287355
288- # Draw a white circular background
289- painter .setBrush (Qt .white )
356+ # Draw a circular background
357+ bg_color = QApplication .palette ().window ().color ().name ()
358+ painter .setBrush (bg_color )
290359 painter .setPen (Qt .NoPen )
291360 painter .drawEllipse (x + 2 , y + 2 , overlay_size - 4 , overlay_size - 4 )
292361
@@ -296,10 +365,10 @@ def apply_icon_overlay(self, pixmap: QPixmap, icon_enum: Any, color: str = "#999
296365
297366 def load_root (self , root_type : str , add_history = True , highlight_fileid : str | None = None , clicked_item_id : str | None = None ):
298367 if root_type == "my_drive" :
299- items = gcache .get_root_my_drive_children ()
368+ items = self . gcache .get_root_my_drive_children ()
300369 self .address_bar .setText ("My Drive" )
301370 else :
302- items = gcache .get_root_shared_with_me_items ()
371+ items = self . gcache .get_root_shared_with_me_items ()
303372 self .address_bar .setText ("Shared with me" )
304373
305374 self .current_folder_id = root_type
@@ -313,7 +382,7 @@ def load_root(self, root_type: str, add_history=True, highlight_fileid: str | No
313382 self .file_view .repaint ()
314383
315384 def load_folder (self , folder_id : str , folder_name : str , add_history = True , highlight_fileid : str | None = None , clicked_item_id : str | None = None ):
316- items = gcache .get_children (folder_id )
385+ items = self . gcache .get_children (folder_id )
317386 self .current_folder_id = folder_id
318387 self .address_bar .setText (folder_name )
319388 if add_history :
@@ -411,7 +480,7 @@ def populate_files(self, items: List[Dict[str, Any]]):
411480 else :
412481 pixmap = get_mime_icon (mime ).pixmap (self .file_view .iconSize ())
413482
414- cache_path = gcache .get_cache_path_for_file (item )
483+ cache_path = self . gcache .get_cache_path_for_file (item )
415484 if cache_path :
416485 if cache_path .exists ():
417486 pixmap = self .apply_icon_overlay (pixmap , FilledIcon .CIRCLE_CHECK )
@@ -474,7 +543,7 @@ def on_thumbnail_loaded(self, file_id: str, img: QImage):
474543 item = self .item_mapping [file_id ]
475544 if item .listWidget () == self .file_view :
476545 file_data = item .data (Qt .UserRole )
477- cache_path = gcache .get_cache_path_for_file (file_data )
546+ cache_path = self . gcache .get_cache_path_for_file (file_data )
478547 if cache_path :
479548 if cache_path .exists ():
480549 pixmap = self .apply_icon_overlay (pixmap , FilledIcon .CIRCLE_CHECK )
@@ -497,11 +566,17 @@ def on_context_menu(self, pos):
497566
498567 file_data = item .data (Qt .UserRole )
499568 menu = QMenu (self )
569+ copy_id_action = menu .addAction ("Copy ID" )
570+ copy_link_action = menu .addAction ("Copy URL" )
500571 open_browser_action = menu .addAction ("Open in browser..." )
501572
502573 action = menu .exec (self .file_view .viewport ().mapToGlobal (pos ))
503- if action == open_browser_action :
504- url = gdrive_base .GENERIC_LINK_PREFIX + file_data ['id' ]
574+ url = gdrive_base .GENERIC_LINK_PREFIX + file_data ['id' ]
575+ if action == copy_id_action :
576+ QApplication .clipboard ().setText (file_data ['id' ])
577+ elif action == copy_link_action :
578+ QApplication .clipboard ().setText (url )
579+ elif action == open_browser_action :
505580 webbrowser .open (url )
506581
507582 def on_item_activated (self , item : QListWidgetItem ):
@@ -515,10 +590,10 @@ def on_item_activated(self, item: QListWidgetItem):
515590 folder_id = file_data ['shortcutDetails' ]['targetId' ]
516591 target_file = None
517592 else :
518- target_file = gcache .get_item (file_data ['shortcutDetails' ]['targetId' ])
593+ target_file = self . gcache .get_item (file_data ['shortcutDetails' ]['targetId' ])
519594 folder_id = target_file ['parent_id' ]
520595 target_file = target_file ['id' ]
521- target_folder = gcache .get_item (folder_id )
596+ target_folder = self . gcache .get_item (folder_id )
522597 if not target_folder :
523598 url = gdrive_base .FOLDER_LINK .format (folder_id )
524599 webbrowser .open (url )
@@ -527,7 +602,7 @@ def on_item_activated(self, item: QListWidgetItem):
527602 self .open_file (file_data )
528603
529604 def open_file (self , file_data : Dict [str , Any ]):
530- cache_path = gcache .get_cache_path_for_file (file_data )
605+ cache_path = self . gcache .get_cache_path_for_file (file_data )
531606 if cache_path and cache_path .exists ():
532607 # Open with default app
533608 if sys .platform .startswith ('linux' ):
0 commit comments