Added skeletal delete and rename actions.

This commit is contained in:
Maxim Stewart 2019-06-10 22:18:30 -05:00
parent f2ccc03151
commit 7fa8d2081e
14 changed files with 363 additions and 168 deletions

View File

@ -6,8 +6,7 @@ Need python 3
# TODO # TODO
<ul> <ul>
<li>Add file rename functionality.</li> <li>Attach copy, cut, and paste signals to the controls menu.</li>
<li>Attach copy, cut, paste, and delete signals to the controls menu.</li>
<li>Add search functionality to the current directory.</li> <li>Add search functionality to the current directory.</li>
<li>Add a settings file to store values.</li> <li>Add a settings file to store values.</li>
<li>Improve icon detection for Steam.</li> <li>Improve icon detection for Steam.</li>

Binary file not shown.

View File

@ -6,12 +6,13 @@ gi.require_version('Gtk', '3.0')
gi.require_version('WebKit2', '4.0') gi.require_version('WebKit2', '4.0')
from gi.repository import Gtk as gtk from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk
from gi.repository import WebKit2 as webkit from gi.repository import WebKit2 as webkit
# Python imports # Python imports
from utils import Settings, Events from utils import Settings, Events
gdk.threads_init()
class Main: class Main:
def __init__(self): def __init__(self):
webkit.WebView() # Needed for glade file to load... webkit.WebView() # Needed for glade file to load...

View File

@ -1,25 +1,26 @@
# Gtk Imports # Gtk Imports
import gi import gi, threading
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0') gi.require_version('Gdk', '3.0')
from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk from gi.repository import Gdk as gdk
# Python imports # Python imports
import threading
from .Grid import Grid from .Grid import Grid
from .Dragging import Dragging from .Dragging import Dragging
from threading import Thread from threading import Thread
gdk.threads_init()
class Events: class Events:
def __init__(self, settings): def __init__(self, settings):
self.settings = settings self.settings = settings
self.builder = self.settings.returnBuilder() self.builder = self.settings.returnBuilder()
self.desktop = self.builder.get_object("Desktop") self.desktop = self.builder.get_object("Desktop")
self.webview = self.builder.get_object("webview") self.webview = self.builder.get_object("webview")
self.desktopPath = self.settings.returnDesktopPath() self.desktopPath = self.settings.returnDesktopPath()
self.settings.setDefaultWebviewSettings(self.webview, self.webview.get_settings()) self.settings.setDefaultWebviewSettings(self.webview, self.webview.get_settings())
self.webview.load_uri(self.settings.returnWebHome()) self.webview.load_uri(self.settings.returnWebHome())
@ -30,19 +31,44 @@ class Events:
selectedDirDialog.add_filter(filefilter) selectedDirDialog.add_filter(filefilter)
selectedDirDialog.set_filename(self.desktopPath) selectedDirDialog.set_filename(self.desktopPath)
self.grid = None
self.selectedFile = None
self.setDir(selectedDirDialog) self.setDir(selectedDirDialog)
def setDir(self, widget, data=None): def setDir(self, widget, data=None):
newPath = widget.get_filename() newPath = widget.get_filename()
Thread(target=Grid(self.desktop, self.settings).generateDirectoryGrid, args=(newPath,)).start() self.grid = Grid(self.desktop, self.settings)
Thread(target=self.grid.generateDirectoryGrid, args=(newPath,)).start()
# Grid(self.desktop, self.settings).generateDirectoryGrid(newPath)
def showGridControlMenu(self, widget, data=None): def showGridControlMenu(self, widget, data=None):
self.selectedFile = widget
popover = self.builder.get_object("gridControlMenu") popover = self.builder.get_object("gridControlMenu")
popover.show_all() popover.show_all()
popover.popup() popover.popup()
# File control events
def renameFile(self, widget, data=None):
newName = widget.get_text().strip()
if data and data.keyval == 65293: # Enter key event
self.grid.renameFile(newName)
elif data == None: # Save button 'event'
self.grid.renameFile(newName)
def deleteFile(self, widget, data=None):
self.grid.deleteFile()
def copyFile(self):
pass
def cutFile(self):
pass
# Webview events
def showWebview(self, widget): def showWebview(self, widget):
self.builder.get_object("webViewer").popup() self.builder.get_object("webViewer").popup()

View File

@ -23,20 +23,44 @@ class FileHandler:
self.MPLAYER_WH = " -xy 1600 -geometry 50%:50% "; self.MPLAYER_WH = " -xy 1600 -geometry 50%:50% ";
self.MPV_WH = " -geometry 50%:50% "; self.MPV_WH = " -geometry 50%:50% ";
self.selectedFile = None
def openFile(self, file): def openFile(self, file):
print("Opening: " + file) print("Opening: " + file)
if file.lower().endswith(self.vids): if file.lower().endswith(self.vids):
subprocess.call([self.MEDIAPLAYER, self.MPV_WH, file]) subprocess.Popen([self.MEDIAPLAYER, self.MPV_WH, file])
elif file.lower().endswith(self.music): elif file.lower().endswith(self.music):
subprocess.call([self.MUSICPLAYER, file]) subprocess.Popen([self.MUSICPLAYER, file])
elif file.lower().endswith(self.images): elif file.lower().endswith(self.images):
subprocess.call([self.IMGVIEWER, file]) subprocess.Popen([self.IMGVIEWER, file])
elif file.lower().endswith(self.txt): elif file.lower().endswith(self.txt):
subprocess.call([self.TEXTVIEWER, file]) subprocess.Popen([self.TEXTVIEWER, file])
elif file.lower().endswith(self.pdf): elif file.lower().endswith(self.pdf):
subprocess.call([self.PDFVIEWER, file]) subprocess.Popen([self.PDFVIEWER, file])
elif file.lower().endswith(self.office): elif file.lower().endswith(self.office):
subprocess.call([self.OFFICEPROG, file]) subprocess.Popen([self.OFFICEPROG, file])
else: else:
subprocess.call(['xdg-open', file]) subprocess.Popen(['xdg-open', file])
def renameFile(self, oldFileName, newFileName):
try:
print("Renaming...")
print(oldFileName + " --> " + newFileName)
return 0
except Exception as e:
print("An error occured renaming the file:")
print(e)
return 1
def deleteFile(self, toDeleteFile):
try:
print("Deleting...")
print(toDeleteFile)
return 0
except Exception as e:
print("An error occured deleting the file:")
print(e)
return 1

View File

@ -9,47 +9,51 @@ from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk from gi.repository import Gdk as gdk
from gi.repository import GObject as gobject from gi.repository import GObject as gobject
# Python imports # Python imports
from .Icon import Icon import os, subprocess, threading, hashlib
from .FileHandler import FileHandler
import os, subprocess
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
from os import listdir from os import listdir
from threading import Thread
from .Icon import Icon
from .FileHandler import FileHandler
gdk.threads_init()
class Grid: class Grid:
def __init__(self, desktop, settings): def __init__(self, desktop, settings):
self.desktop = desktop self.desktop = desktop
self.settings = settings self.settings = settings
self.filehandler = FileHandler() self.filehandler = FileHandler()
self.currentPath = "" self.usrHome = settings.returnUserHome()
self.builder = self.settings.returnBuilder() self.builder = self.settings.returnBuilder()
self.ColumnSize = self.settings.returnColumnSize() self.ColumnSize = self.settings.returnColumnSize()
self.thubnailGen = self.settings.getThumbnailGenerator()
self.currentPath = ""
self.selectedFile = ""
def generateDirectoryGrid(self, dirPath): def generateDirectoryGrid(self, dirPath):
dirPaths = ['.', '..'] loadProgress = self.builder.get_object('loadProgress')
files = [] loadProgress.set_text("Loading...")
loadProgress.set_fraction(0.0)
# self.desktop.connect("button_press_event", self.showGridControlMenu, ()) self.clearGrid(self.desktop)
self.currentPath = dirPath
dirPaths = ['.', '..']
files = []
for f in listdir(dirPath): for f in listdir(dirPath):
file = join(dirPath, f) file = join(dirPath, f)
if self.settings.isHideHiddenFiles(): if self.settings.isHideHiddenFiles():
if f.startswith('.'): if f.startswith('.'):
continue continue
if isfile(file): if isfile(file):
files.append(f) files.append(f)
else: else:
dirPaths.append(f) dirPaths.append(f)
dirPaths.sort() vidsList = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm')
files.sort()
files = dirPaths + files
fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files)
tickCount = 0.0 tickCount = 0.0
row = 0 row = 0
@ -57,17 +61,24 @@ class Grid:
x = 0 x = 0
y = 0 y = 0
loadProgress = self.builder.get_object('loadProgress') dirPaths.sort()
loadProgress.set_text("Loading...") files.sort()
loadProgress.set_fraction(0.0) files = dirPaths + files
self.clearGrid(self.desktop)
for file in files: for file in files:
eveBox = Icon(self.settings).createIcon(dirPath, file) eveBox = gtk.EventBox()
# self.drag.connectEvents(self.desktop, eveBox)
eveBox.connect("button_press_event", self.iconClickEventManager, (eveBox,))
eveBox.connect("enter_notify_event", self.settings.mouseOver, ())
eveBox.connect("leave_notify_event", self.settings.mouseOut, ())
# Generate any thumbnails beforehand...
if file.lower().endswith(vidsList):
fullPathFile = dirPath + "/" + file
fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest()
hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png"
if isfile(hashImgpth) == False:
self.generateVideoThumbnail(fullPathFile, hashImgpth)
eveBox = self.generateIcon(dirPath, file, col, row)
else:
eveBox = self.generateIcon(dirPath, file, col, row)
eveBox.show_all()
gobject.idle_add(self.addToGrid, (self.desktop, eveBox, col, row,)) gobject.idle_add(self.addToGrid, (self.desktop, eveBox, col, row,))
tickCount = tickCount + fractionTick tickCount = tickCount + fractionTick
loadProgress.set_fraction(tickCount) loadProgress.set_fraction(tickCount)
@ -77,9 +88,17 @@ class Grid:
col = 0 col = 0
row += 1 row += 1
self.desktop.show_all()
loadProgress.set_text("Finished...") loadProgress.set_text("Finished...")
def generateIcon(self, dirPath, file, col, row):
eveBox = Icon(self.settings).createIcon(dirPath, file)
# self.drag.connectEvents(self.desktop, eveBox)
eveBox.connect("button_press_event", self.iconClickEventManager, (eveBox,))
eveBox.connect("enter_notify_event", self.settings.mouseOver, ())
eveBox.connect("leave_notify_event", self.settings.mouseOut, ())
return eveBox
def addToGrid(self, args): def addToGrid(self, args):
args[0].attach(args[1], args[2], args[3], 1, 1) args[0].attach(args[1], args[2], args[3], 1, 1)
@ -91,31 +110,63 @@ class Grid:
break break
def iconClickEventManager(self, widget, eve, params): def iconClickEventManager(self, widget, eve, params):
self.settings.setSelected(params[0]) try:
if eve.type == gdk.EventType.DOUBLE_BUTTON_PRESS: self.settings.setSelected(params[0])
children = widget.get_children()[0].get_children() children = widget.get_children()[0].get_children()
fileName = children[1].get_text() fileName = children[1].get_text()
dir = self.currentPath dir = self.currentPath
file = dir + "/" + fileName file = dir + "/" + fileName
if fileName == ".": if eve.type == gdk.EventType.DOUBLE_BUTTON_PRESS:
self.generateDirectoryGrid(dir) if fileName == ".":
elif fileName == "..": self.setNewPath(dir)
parentDir = os.path.abspath(os.path.join(dir, os.pardir)) elif fileName == "..":
self.currentPath = parentDir parentDir = os.path.abspath(os.path.join(dir, os.pardir))
self.generateDirectoryGrid(parentDir) self.currentPath = parentDir
elif isdir(file): self.setNewPath(parentDir)
self.currentPath = file elif isdir(file):
Thread(target=self.generateDirectoryGrid, args=(self.currentPath,)).start() self.currentPath = file
else: self.setNewPath(self.currentPath)
self.filehandler.openFile(file) elif isfile(file):
elif eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3: self.filehandler.openFile(file)
children = widget.get_children()[0].get_children() elif eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3:
input = self.builder.get_object("iconRenameInput") input = self.builder.get_object("iconRenameInput")
popover = self.builder.get_object("iconControlsWindow") popover = self.builder.get_object("iconControlsWindow")
self.selectedFile = file # Used for return to caller
input.set_text(children[1].get_text()) input.set_text(fileName)
popover.set_relative_to(children[1]) popover.set_relative_to(children[1])
popover.set_position(gtk.PositionType.RIGHT) popover.set_position(gtk.PositionType.RIGHT)
popover.show_all() popover.show_all()
popover.popup() popover.popup()
except Exception as e:
print(e)
def generateVideoThumbnail(self, fullPathFile, hashImgpth):
subprocess.call([self.thubnailGen, "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth])
def setNewPath(self, path):
self.generateDirectoryGrid(path)
# NOTE: Threading here causes seg faults. My theory is that
# the calling threading dies b/c the grid itself is cleard
# of children and the child is the one that has the 'thread'
#
# Thread(target=self.generateDirectoryGrid, args=(path,)).start()
# Pass through file control events
def renameFile(self, file):
newName = self.currentPath + "/" + file
status = self.filehandler.renameFile(self.selectedFile, newName)
if status == 0:
self.selectedFile = newName
self.generateDirectoryGrid(self.currentPath)
def deleteFile(self):
status = self.filehandler.deleteFile(self.selectedFile)
if status == 0:
self.selectedFile = ""
self.generateDirectoryGrid(self.currentPath)

View File

@ -8,7 +8,7 @@ from gi.repository import Gtk as gtk
from gi.repository import Gio as gio from gi.repository import Gio as gio
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
import os, subprocess, hashlib import os, hashlib
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
@ -51,10 +51,7 @@ class Icon:
if file.lower().endswith(vidsList): if file.lower().endswith(vidsList):
fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest() fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest()
hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png" hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png"
if isfile(hashImgpth) == False: thumbnl = self.createIconImageFromBuffer(hashImgpth, self.viIconWxH)
self.generateVideoThumbnail(fullPathFile, hashImgpth)
thumbnl = self.createIconImageFromBuffer(hashImgpth, self.viIconWxH)
elif file.lower().endswith(imagesList): elif file.lower().endswith(imagesList):
thumbnl = self.createIconImageFromBuffer(fullPathFile, self.viIconWxH) thumbnl = self.createIconImageFromBuffer(fullPathFile, self.viIconWxH)
else: else:
@ -76,9 +73,6 @@ class Icon:
return gtk.Image() return gtk.Image()
def generateVideoThumbnail(self, fullPathFile, hashImgpth):
subprocess.call(["ffmpegthumbnailer", "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth])
def getSystemThumbnail(self, filename,size): def getSystemThumbnail(self, filename,size):
final_filename = "" final_filename = ""
if os.path.exists(filename): if os.path.exists(filename):

View File

@ -16,16 +16,17 @@ class Settings:
self.DEFAULTCOLOR = gdk.RGBA(0.0, 0.0, 0.0, 0.0) # ~#00000000 self.DEFAULTCOLOR = gdk.RGBA(0.0, 0.0, 0.0, 0.0) # ~#00000000
self.MOUSEOVERCOLOR = gdk.RGBA(0.0, 0.9, 1.0, 0.64) # ~#00e8ff self.MOUSEOVERCOLOR = gdk.RGBA(0.0, 0.9, 1.0, 0.64) # ~#00e8ff
self.SELECTEDCOLOR = gdk.RGBA(0.4, 0.5, 0.1, 0.84) self.SELECTEDCOLOR = gdk.RGBA(0.4, 0.5, 0.1, 0.84)
self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1)
self.THUMB_GENERATOR = "ffmpegthumbnailer"
self.hideHiddenFiles = True self.hideHiddenFiles = True
self.usrHome = os.path.expanduser('~') self.webHome = 'http://webfm.com/'
self.desktopPath = self.usrHome + "/Desktop" self.usrHome = os.path.expanduser('~')
self.ColumnSize = 10 self.desktopPath = self.usrHome + "/Desktop"
self.webHome = 'http://webfm.com/' self.iconContainerWxH = [128, 128]
self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1)
self.iconContainerWxH = [128, -1]
self.systemIconImageWxH = [72, 72] self.systemIconImageWxH = [72, 72]
self.viIconWxH = [128, -1] self.viIconWxH = [256, 128]
self.ColumnSize = 8
def attachBuilder(self, builder): def attachBuilder(self, builder):
@ -70,8 +71,9 @@ class Settings:
def returnBuilder(self): return self.builder def returnBuilder(self): return self.builder
def returnUserHome(self): return self.usrHome def returnUserHome(self): return self.usrHome
def returnDesktopPath(self): return self.usrHome + "/Desktop" def returnDesktopPath(self): return self.usrHome + "/Desktop"
def returnColumnSize(self): return self.ColumnSize
def returnIconImagePos(self): return self.GTK_ORIENTATION def returnIconImagePos(self): return self.GTK_ORIENTATION
def getThumbnailGenerator(self): return self.THUMB_GENERATOR
def returnColumnSize(self): return self.ColumnSize
def returnContainerWH(self): return self.iconContainerWxH def returnContainerWH(self): return self.iconContainerWxH
def returnSystemIconImageWH(self): return self.systemIconImageWxH def returnSystemIconImageWH(self): return self.systemIconImageWxH
def returnVIIconWH(self): return self.viIconWxH def returnVIIconWH(self): return self.viIconWxH

View File

@ -6,12 +6,13 @@ gi.require_version('Gtk', '3.0')
gi.require_version('WebKit2', '4.0') gi.require_version('WebKit2', '4.0')
from gi.repository import Gtk as gtk from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk
from gi.repository import WebKit2 as webkit from gi.repository import WebKit2 as webkit
# Python imports # Python imports
from utils import Settings, Events from utils import Settings, Events
gdk.threads_init()
class Main: class Main:
def __init__(self): def __init__(self):
webkit.WebView() # Needed for glade file to load... webkit.WebView() # Needed for glade file to load...

View File

@ -1,25 +1,26 @@
# Gtk Imports # Gtk Imports
import gi import gi, threading
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0') gi.require_version('Gdk', '3.0')
from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk from gi.repository import Gdk as gdk
# Python imports # Python imports
import threading
from .Grid import Grid from .Grid import Grid
from .Dragging import Dragging from .Dragging import Dragging
from threading import Thread from threading import Thread
gdk.threads_init()
class Events: class Events:
def __init__(self, settings): def __init__(self, settings):
self.settings = settings self.settings = settings
self.builder = self.settings.returnBuilder() self.builder = self.settings.returnBuilder()
self.desktop = self.builder.get_object("Desktop") self.desktop = self.builder.get_object("Desktop")
self.webview = self.builder.get_object("webview") self.webview = self.builder.get_object("webview")
self.desktopPath = self.settings.returnDesktopPath() self.desktopPath = self.settings.returnDesktopPath()
self.settings.setDefaultWebviewSettings(self.webview, self.webview.get_settings()) self.settings.setDefaultWebviewSettings(self.webview, self.webview.get_settings())
self.webview.load_uri(self.settings.returnWebHome()) self.webview.load_uri(self.settings.returnWebHome())
@ -30,19 +31,44 @@ class Events:
selectedDirDialog.add_filter(filefilter) selectedDirDialog.add_filter(filefilter)
selectedDirDialog.set_filename(self.desktopPath) selectedDirDialog.set_filename(self.desktopPath)
self.grid = None
self.selectedFile = None
self.setDir(selectedDirDialog) self.setDir(selectedDirDialog)
def setDir(self, widget, data=None): def setDir(self, widget, data=None):
newPath = widget.get_filename() newPath = widget.get_filename()
Thread(target=Grid(self.desktop, self.settings).generateDirectoryGrid, args=(newPath,)).start() self.grid = Grid(self.desktop, self.settings)
Thread(target=self.grid.generateDirectoryGrid, args=(newPath,)).start()
# Grid(self.desktop, self.settings).generateDirectoryGrid(newPath)
def showGridControlMenu(self, widget, data=None): def showGridControlMenu(self, widget, data=None):
self.selectedFile = widget
popover = self.builder.get_object("gridControlMenu") popover = self.builder.get_object("gridControlMenu")
popover.show_all() popover.show_all()
popover.popup() popover.popup()
# File control events
def renameFile(self, widget, data=None):
newName = widget.get_text().strip()
if data and data.keyval == 65293: # Enter key event
self.grid.renameFile(newName)
elif data == None: # Save button 'event'
self.grid.renameFile(newName)
def deleteFile(self, widget, data=None):
self.grid.deleteFile()
def copyFile(self):
pass
def cutFile(self):
pass
# Webview events
def showWebview(self, widget): def showWebview(self, widget):
self.builder.get_object("webViewer").popup() self.builder.get_object("webViewer").popup()

View File

@ -23,20 +23,44 @@ class FileHandler:
self.MPLAYER_WH = " -xy 1600 -geometry 50%:50% "; self.MPLAYER_WH = " -xy 1600 -geometry 50%:50% ";
self.MPV_WH = " -geometry 50%:50% "; self.MPV_WH = " -geometry 50%:50% ";
self.selectedFile = None
def openFile(self, file): def openFile(self, file):
print("Opening: " + file) print("Opening: " + file)
if file.lower().endswith(self.vids): if file.lower().endswith(self.vids):
subprocess.call([self.MEDIAPLAYER, self.MPV_WH, file]) subprocess.Popen([self.MEDIAPLAYER, self.MPV_WH, file])
elif file.lower().endswith(self.music): elif file.lower().endswith(self.music):
subprocess.call([self.MUSICPLAYER, file]) subprocess.Popen([self.MUSICPLAYER, file])
elif file.lower().endswith(self.images): elif file.lower().endswith(self.images):
subprocess.call([self.IMGVIEWER, file]) subprocess.Popen([self.IMGVIEWER, file])
elif file.lower().endswith(self.txt): elif file.lower().endswith(self.txt):
subprocess.call([self.TEXTVIEWER, file]) subprocess.Popen([self.TEXTVIEWER, file])
elif file.lower().endswith(self.pdf): elif file.lower().endswith(self.pdf):
subprocess.call([self.PDFVIEWER, file]) subprocess.Popen([self.PDFVIEWER, file])
elif file.lower().endswith(self.office): elif file.lower().endswith(self.office):
subprocess.call([self.OFFICEPROG, file]) subprocess.Popen([self.OFFICEPROG, file])
else: else:
subprocess.call(['xdg-open', file]) subprocess.Popen(['xdg-open', file])
def renameFile(self, oldFileName, newFileName):
try:
print("Renaming...")
print(oldFileName + " --> " + newFileName)
return 0
except Exception as e:
print("An error occured renaming the file:")
print(e)
return 1
def deleteFile(self, toDeleteFile):
try:
print("Deleting...")
print(toDeleteFile)
return 0
except Exception as e:
print("An error occured deleting the file:")
print(e)
return 1

View File

@ -9,47 +9,51 @@ from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk from gi.repository import Gdk as gdk
from gi.repository import GObject as gobject from gi.repository import GObject as gobject
# Python imports # Python imports
from .Icon import Icon import os, subprocess, threading, hashlib
from .FileHandler import FileHandler
import os, subprocess
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
from os import listdir from os import listdir
from threading import Thread
from .Icon import Icon
from .FileHandler import FileHandler
gdk.threads_init()
class Grid: class Grid:
def __init__(self, desktop, settings): def __init__(self, desktop, settings):
self.desktop = desktop self.desktop = desktop
self.settings = settings self.settings = settings
self.filehandler = FileHandler() self.filehandler = FileHandler()
self.currentPath = "" self.usrHome = settings.returnUserHome()
self.builder = self.settings.returnBuilder() self.builder = self.settings.returnBuilder()
self.ColumnSize = self.settings.returnColumnSize() self.ColumnSize = self.settings.returnColumnSize()
self.thubnailGen = self.settings.getThumbnailGenerator()
self.currentPath = ""
self.selectedFile = ""
def generateDirectoryGrid(self, dirPath): def generateDirectoryGrid(self, dirPath):
dirPaths = ['.', '..'] loadProgress = self.builder.get_object('loadProgress')
files = [] loadProgress.set_text("Loading...")
loadProgress.set_fraction(0.0)
# self.desktop.connect("button_press_event", self.showGridControlMenu, ()) self.clearGrid(self.desktop)
self.currentPath = dirPath
dirPaths = ['.', '..']
files = []
for f in listdir(dirPath): for f in listdir(dirPath):
file = join(dirPath, f) file = join(dirPath, f)
if self.settings.isHideHiddenFiles(): if self.settings.isHideHiddenFiles():
if f.startswith('.'): if f.startswith('.'):
continue continue
if isfile(file): if isfile(file):
files.append(f) files.append(f)
else: else:
dirPaths.append(f) dirPaths.append(f)
dirPaths.sort() vidsList = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm')
files.sort()
files = dirPaths + files
fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files) fractionTick = 1.0 / 1.0 if len(files) == 0 else len(files)
tickCount = 0.0 tickCount = 0.0
row = 0 row = 0
@ -57,17 +61,24 @@ class Grid:
x = 0 x = 0
y = 0 y = 0
loadProgress = self.builder.get_object('loadProgress') dirPaths.sort()
loadProgress.set_text("Loading...") files.sort()
loadProgress.set_fraction(0.0) files = dirPaths + files
self.clearGrid(self.desktop)
for file in files: for file in files:
eveBox = Icon(self.settings).createIcon(dirPath, file) eveBox = gtk.EventBox()
# self.drag.connectEvents(self.desktop, eveBox)
eveBox.connect("button_press_event", self.iconClickEventManager, (eveBox,))
eveBox.connect("enter_notify_event", self.settings.mouseOver, ())
eveBox.connect("leave_notify_event", self.settings.mouseOut, ())
# Generate any thumbnails beforehand...
if file.lower().endswith(vidsList):
fullPathFile = dirPath + "/" + file
fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest()
hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png"
if isfile(hashImgpth) == False:
self.generateVideoThumbnail(fullPathFile, hashImgpth)
eveBox = self.generateIcon(dirPath, file, col, row)
else:
eveBox = self.generateIcon(dirPath, file, col, row)
eveBox.show_all()
gobject.idle_add(self.addToGrid, (self.desktop, eveBox, col, row,)) gobject.idle_add(self.addToGrid, (self.desktop, eveBox, col, row,))
tickCount = tickCount + fractionTick tickCount = tickCount + fractionTick
loadProgress.set_fraction(tickCount) loadProgress.set_fraction(tickCount)
@ -77,9 +88,17 @@ class Grid:
col = 0 col = 0
row += 1 row += 1
self.desktop.show_all()
loadProgress.set_text("Finished...") loadProgress.set_text("Finished...")
def generateIcon(self, dirPath, file, col, row):
eveBox = Icon(self.settings).createIcon(dirPath, file)
# self.drag.connectEvents(self.desktop, eveBox)
eveBox.connect("button_press_event", self.iconClickEventManager, (eveBox,))
eveBox.connect("enter_notify_event", self.settings.mouseOver, ())
eveBox.connect("leave_notify_event", self.settings.mouseOut, ())
return eveBox
def addToGrid(self, args): def addToGrid(self, args):
args[0].attach(args[1], args[2], args[3], 1, 1) args[0].attach(args[1], args[2], args[3], 1, 1)
@ -91,31 +110,63 @@ class Grid:
break break
def iconClickEventManager(self, widget, eve, params): def iconClickEventManager(self, widget, eve, params):
self.settings.setSelected(params[0]) try:
if eve.type == gdk.EventType.DOUBLE_BUTTON_PRESS: self.settings.setSelected(params[0])
children = widget.get_children()[0].get_children() children = widget.get_children()[0].get_children()
fileName = children[1].get_text() fileName = children[1].get_text()
dir = self.currentPath dir = self.currentPath
file = dir + "/" + fileName file = dir + "/" + fileName
if fileName == ".": if eve.type == gdk.EventType.DOUBLE_BUTTON_PRESS:
self.generateDirectoryGrid(dir) if fileName == ".":
elif fileName == "..": self.setNewPath(dir)
parentDir = os.path.abspath(os.path.join(dir, os.pardir)) elif fileName == "..":
self.currentPath = parentDir parentDir = os.path.abspath(os.path.join(dir, os.pardir))
self.generateDirectoryGrid(parentDir) self.currentPath = parentDir
elif isdir(file): self.setNewPath(parentDir)
self.currentPath = file elif isdir(file):
Thread(target=self.generateDirectoryGrid, args=(self.currentPath,)).start() self.currentPath = file
else: self.setNewPath(self.currentPath)
self.filehandler.openFile(file) elif isfile(file):
elif eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3: self.filehandler.openFile(file)
children = widget.get_children()[0].get_children() elif eve.type == gdk.EventType.BUTTON_PRESS and eve.button == 3:
input = self.builder.get_object("iconRenameInput") input = self.builder.get_object("iconRenameInput")
popover = self.builder.get_object("iconControlsWindow") popover = self.builder.get_object("iconControlsWindow")
self.selectedFile = file # Used for return to caller
input.set_text(children[1].get_text()) input.set_text(fileName)
popover.set_relative_to(children[1]) popover.set_relative_to(children[1])
popover.set_position(gtk.PositionType.RIGHT) popover.set_position(gtk.PositionType.RIGHT)
popover.show_all() popover.show_all()
popover.popup() popover.popup()
except Exception as e:
print(e)
def generateVideoThumbnail(self, fullPathFile, hashImgpth):
subprocess.call([self.thubnailGen, "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth])
def setNewPath(self, path):
self.generateDirectoryGrid(path)
# NOTE: Threading here causes seg faults. My theory is that
# the calling threading dies b/c the grid itself is cleard
# of children and the child is the one that has the 'thread'
#
# Thread(target=self.generateDirectoryGrid, args=(path,)).start()
# Pass through file control events
def renameFile(self, file):
newName = self.currentPath + "/" + file
status = self.filehandler.renameFile(self.selectedFile, newName)
if status == 0:
self.selectedFile = newName
self.generateDirectoryGrid(self.currentPath)
def deleteFile(self):
status = self.filehandler.deleteFile(self.selectedFile)
if status == 0:
self.selectedFile = ""
self.generateDirectoryGrid(self.currentPath)

View File

@ -8,7 +8,7 @@ from gi.repository import Gtk as gtk
from gi.repository import Gio as gio from gi.repository import Gio as gio
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
import os, subprocess, hashlib import os, hashlib
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
@ -51,10 +51,7 @@ class Icon:
if file.lower().endswith(vidsList): if file.lower().endswith(vidsList):
fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest() fileHash = hashlib.sha256(str.encode(fullPathFile)).hexdigest()
hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png" hashImgpth = self.usrHome + "/.thumbnails/normal/" + fileHash + ".png"
if isfile(hashImgpth) == False: thumbnl = self.createIconImageFromBuffer(hashImgpth, self.viIconWxH)
self.generateVideoThumbnail(fullPathFile, hashImgpth)
thumbnl = self.createIconImageFromBuffer(hashImgpth, self.viIconWxH)
elif file.lower().endswith(imagesList): elif file.lower().endswith(imagesList):
thumbnl = self.createIconImageFromBuffer(fullPathFile, self.viIconWxH) thumbnl = self.createIconImageFromBuffer(fullPathFile, self.viIconWxH)
else: else:
@ -76,9 +73,6 @@ class Icon:
return gtk.Image() return gtk.Image()
def generateVideoThumbnail(self, fullPathFile, hashImgpth):
subprocess.call(["ffmpegthumbnailer", "-t", "65%", "-s", "300", "-c", "jpg", "-i", fullPathFile, "-o", hashImgpth])
def getSystemThumbnail(self, filename,size): def getSystemThumbnail(self, filename,size):
final_filename = "" final_filename = ""
if os.path.exists(filename): if os.path.exists(filename):

View File

@ -16,16 +16,17 @@ class Settings:
self.DEFAULTCOLOR = gdk.RGBA(0.0, 0.0, 0.0, 0.0) # ~#00000000 self.DEFAULTCOLOR = gdk.RGBA(0.0, 0.0, 0.0, 0.0) # ~#00000000
self.MOUSEOVERCOLOR = gdk.RGBA(0.0, 0.9, 1.0, 0.64) # ~#00e8ff self.MOUSEOVERCOLOR = gdk.RGBA(0.0, 0.9, 1.0, 0.64) # ~#00e8ff
self.SELECTEDCOLOR = gdk.RGBA(0.4, 0.5, 0.1, 0.84) self.SELECTEDCOLOR = gdk.RGBA(0.4, 0.5, 0.1, 0.84)
self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1)
self.THUMB_GENERATOR = "ffmpegthumbnailer"
self.hideHiddenFiles = True self.hideHiddenFiles = True
self.usrHome = os.path.expanduser('~') self.webHome = 'http://webfm.com/'
self.desktopPath = self.usrHome + "/Desktop" self.usrHome = os.path.expanduser('~')
self.ColumnSize = 10 self.desktopPath = self.usrHome + "/Desktop"
self.webHome = 'http://webfm.com/' self.iconContainerWxH = [128, 128]
self.GTK_ORIENTATION = 1 # HORIZONTAL (0) VERTICAL (1)
self.iconContainerWxH = [128, -1]
self.systemIconImageWxH = [72, 72] self.systemIconImageWxH = [72, 72]
self.viIconWxH = [128, -1] self.viIconWxH = [256, 128]
self.ColumnSize = 8
def attachBuilder(self, builder): def attachBuilder(self, builder):
@ -70,8 +71,9 @@ class Settings:
def returnBuilder(self): return self.builder def returnBuilder(self): return self.builder
def returnUserHome(self): return self.usrHome def returnUserHome(self): return self.usrHome
def returnDesktopPath(self): return self.usrHome + "/Desktop" def returnDesktopPath(self): return self.usrHome + "/Desktop"
def returnColumnSize(self): return self.ColumnSize
def returnIconImagePos(self): return self.GTK_ORIENTATION def returnIconImagePos(self): return self.GTK_ORIENTATION
def getThumbnailGenerator(self): return self.THUMB_GENERATOR
def returnColumnSize(self): return self.ColumnSize
def returnContainerWH(self): return self.iconContainerWxH def returnContainerWH(self): return self.iconContainerWxH
def returnSystemIconImageWH(self): return self.systemIconImageWxH def returnSystemIconImageWH(self): return self.systemIconImageWxH
def returnVIIconWH(self): return self.viIconWxH def returnVIIconWH(self): return self.viIconWxH