223 lines
7.7 KiB
Python
223 lines
7.7 KiB
Python
# Python imports
|
|
import os, threading, time
|
|
from os.path import isdir, isfile, join
|
|
from os import listdir
|
|
|
|
|
|
# Lib imports
|
|
import gi
|
|
gi.require_version('Gtk', '3.0')
|
|
gi.require_version('Gdk', '3.0')
|
|
|
|
from gi.repository import Gtk
|
|
from gi.repository import Gdk
|
|
from gi.repository import GLib
|
|
from gi.repository import Gio
|
|
from gi.repository import GdkPixbuf
|
|
|
|
|
|
# Application imports
|
|
from .icon import Icon
|
|
from utils.file_handler import FileHandler
|
|
|
|
|
|
def threaded(fn):
|
|
def wrapper(*args, **kwargs):
|
|
threading.Thread(target=fn, args=args, kwargs=kwargs).start()
|
|
return wrapper
|
|
|
|
|
|
class Grid:
|
|
def __init__(self, _grid, _settings):
|
|
self.grid = _grid
|
|
self.settings = _settings
|
|
self.fileHandler = FileHandler(self.settings)
|
|
|
|
self.store = Gtk.ListStore(GdkPixbuf.Pixbuf or None, str)
|
|
self.usrHome = self.settings.get_user_home()
|
|
self.hideHiddenFiles = self.settings.isHideHiddenFiles()
|
|
self.builder = self.settings.get_builder()
|
|
self.ColumnSize = self.settings.getColumnSize()
|
|
self.vidsFilter = self.settings.getVidsFilter()
|
|
self.imagesFilter = self.settings.getImagesFilter()
|
|
self.iconFactory = Icon(self.settings)
|
|
self.selectedFiles = []
|
|
self.currentPath = ""
|
|
|
|
self.grid.set_model(self.store)
|
|
self.grid.set_pixbuf_column(0)
|
|
self.grid.set_text_column(1)
|
|
self.grid.connect("item-activated", self.iconDblLeftClick)
|
|
self.grid.connect("button_release_event", self.iconSingleClick, (self.grid,))
|
|
|
|
def setNewDirectory(self, path):
|
|
self.store.clear()
|
|
self.currentPath = path
|
|
dirPaths = ['.', '..']
|
|
vids = []
|
|
images = []
|
|
desktop = []
|
|
files = []
|
|
|
|
for f in listdir(path):
|
|
file = join(path, f)
|
|
if self.hideHiddenFiles:
|
|
if f.startswith('.'):
|
|
continue
|
|
|
|
if isfile(file):
|
|
lowerName = file.lower()
|
|
|
|
if lowerName.endswith(self.vidsFilter):
|
|
vids.append(f)
|
|
elif lowerName.endswith(self.imagesFilter):
|
|
images.append(f)
|
|
elif lowerName.endswith((".desktop",)):
|
|
desktop.append(f)
|
|
else:
|
|
files.append(f)
|
|
else:
|
|
dirPaths.append(f)
|
|
|
|
dirPaths.sort()
|
|
vids.sort()
|
|
images.sort()
|
|
desktop.sort()
|
|
files.sort()
|
|
|
|
files = dirPaths + vids + images + desktop + files
|
|
self.generateGridIcons(path, files)
|
|
|
|
|
|
def generateGridIcons(self, dir, files):
|
|
# NOTE: We insure all indecies exist before calling threads that update
|
|
# icon positions. In addition, adding the name allows us to see
|
|
# the "file" during long or heavy number of icon updates.
|
|
for file in files:
|
|
self.store.append([None, file])
|
|
|
|
# Now we update as fast as possible the icons.
|
|
for i, file in enumerate(files):
|
|
self.create_icon(i, dir, file)
|
|
|
|
@threaded
|
|
def create_icon(self, i, dir, file):
|
|
icon = self.iconFactory.create_icon(dir, file)
|
|
GLib.idle_add(self.update_store, *(i, icon, dir, file,))
|
|
|
|
def update_store(self, i, icon, dir, file):
|
|
fpath = f"{dir}/{file}"
|
|
itr = self.store.get_iter(i)
|
|
|
|
if not icon:
|
|
icon = self.get_system_thumbnail(fpath, self.iconFactory.SYS_ICON_WH[0])
|
|
if not icon:
|
|
if fpath.endswith(".gif"):
|
|
icon = GdkPixbuf.PixbufAnimation.get_static_image(fpath)
|
|
else:
|
|
icon = GdkPixbuf.Pixbuf.new_from_file(self.iconFactory.INTERNAL_ICON_PTH)
|
|
|
|
self.store.set_value(itr, 0, icon)
|
|
|
|
def get_system_thumbnail(self, filename, size):
|
|
try:
|
|
if os.path.exists(filename):
|
|
gioFile = Gio.File.new_for_path(filename)
|
|
info = gioFile.query_info('standard::icon' , 0, Gio.Cancellable())
|
|
icon = info.get_icon().get_names()[0]
|
|
iconTheme = Gtk.IconTheme.get_default()
|
|
iconData = iconTheme.lookup_icon(icon , size , 0)
|
|
if iconData:
|
|
iconPath = iconData.get_filename()
|
|
return GdkPixbuf.Pixbuf.new_from_file(iconPath)
|
|
else:
|
|
return None
|
|
else:
|
|
return None
|
|
except Exception as e:
|
|
print("System icon generation issue:")
|
|
print( repr(e) )
|
|
return None
|
|
|
|
|
|
def iconDblLeftClick(self, widget, item):
|
|
try:
|
|
model = widget.get_model()
|
|
fileName = model[item][1]
|
|
dir = self.currentPath
|
|
file = dir + "/" + fileName
|
|
|
|
if fileName == ".":
|
|
self.setNewDirectory(dir)
|
|
elif fileName == "..":
|
|
parentDir = os.path.abspath(os.path.join(dir, os.pardir))
|
|
self.currentPath = parentDir
|
|
self.setNewDirectory(parentDir)
|
|
self.self.settings.saveSettings(parentDir)
|
|
elif isdir(file):
|
|
self.currentPath = file
|
|
self.setNewDirectory(self.currentPath)
|
|
self.self.settings.saveSettings(self.currentPath)
|
|
elif isfile(file):
|
|
self.fileHandler.openFile(file)
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
def iconSingleClick(self, widget, eve, rclicked_icon):
|
|
try:
|
|
if eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 1:
|
|
self.selectedFiles.clear()
|
|
items = widget.get_selected_items()
|
|
model = widget.get_model()
|
|
dir = self.currentPath
|
|
|
|
for item in items:
|
|
fileName = model[item][1]
|
|
|
|
if fileName != "." and fileName != "..":
|
|
file = dir + "/" + fileName
|
|
self.selectedFiles.append(file) # Used for return to caller
|
|
|
|
elif eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 3:
|
|
input = self.builder.get_object("filenameInput")
|
|
controls = self.builder.get_object("iconControlsWindow")
|
|
iconsButtonBox = self.builder.get_object("iconsButtonBox")
|
|
menuButtonBox = self.builder.get_object("menuButtonBox")
|
|
|
|
|
|
if len(self.selectedFiles) == 1:
|
|
parts = self.selectedFiles[0].split("/")
|
|
input.set_text(parts[len(parts) - 1])
|
|
input.show()
|
|
iconsButtonBox.show()
|
|
menuButtonBox.hide()
|
|
controls.show()
|
|
elif len(self.selectedFiles) > 1:
|
|
input.set_text("")
|
|
input.hide()
|
|
menuButtonBox.hide()
|
|
iconsButtonBox.show()
|
|
controls.show()
|
|
else:
|
|
input.set_text("")
|
|
input.show()
|
|
menuButtonBox.show()
|
|
iconsButtonBox.hide()
|
|
controls.show()
|
|
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
def returnSelectedFiles(self):
|
|
# NOTE: Just returning selectedFiles looks like it returns a "pointer"
|
|
# to the children. This means we lose the list if any left click occures
|
|
# in this class.
|
|
files = []
|
|
for file in self.selectedFiles:
|
|
files.append(file)
|
|
return files
|
|
|
|
def returnCurrentPath(self):
|
|
currentPath = self.currentPath
|
|
return currentPath
|