Pytop/src/Pytop/widgets/grid.py

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