Perliminary properties viewer plugin

This commit is contained in:
itdominator 2022-07-16 02:33:25 -05:00
parent bcc04dda3c
commit b1bf8785c6
7 changed files with 1050 additions and 77 deletions

View File

@ -1,17 +1,17 @@
### Note ### Note
Copy the example and rename it to your desired name. Plugins define a ui target slot with the 'ui_target' permissions data but don't have to if not directly interacted with. Copy the example and rename it to your desired name. Plugins define a ui target slot with the 'ui_target' requests data but don't have to if not directly interacted with.
Plugins must have a run method defined; though, you do not need to necessarily do anything within it. The run method implies that the passed in event system or other data is ready for the plugin to use. Plugins must have a run method defined; though, you do not need to necessarily do anything within it. The run method implies that the passed in event system or other data is ready for the plugin to use.
### Manifest Example (All are required.) ### Manifest Example (All are required even if empty.)
``` ```
class Manifest: class Manifest:
path: str = os.path.dirname(os.path.realpath(__file__)) path: str = os.path.dirname(os.path.realpath(__file__))
name: str = "Example Plugin" name: str = "Example Plugin"
author: str = "John Doe" author: str = "John Doe"
version: str = "0.0.1" version: str = "0.0.1"
support: str = "" support: str = ""
permissions: {} = { requests: {} = {
'ui_target': "plugin_control_list", 'ui_target': "plugin_control_list",
'pass_fm_events': "true" 'pass_fm_events': "true"
@ -19,9 +19,9 @@ class Manifest:
``` ```
### Permissions ### Requests
``` ```
permissions: {} = { requests: {} = {
'ui_target': "plugin_control_list", 'ui_target': "plugin_control_list",
'ui_target_id': "<some other Gtk Glade ID>" # Only needed if using "other" in "ui_target". See below for predefined "ui_target" options... 'ui_target_id': "<some other Gtk Glade ID>" # Only needed if using "other" in "ui_target". See below for predefined "ui_target" options...
'pass_fm_events': "true" # If empty or not present will be ignored. 'pass_fm_events': "true" # If empty or not present will be ignored.

View File

@ -0,0 +1,685 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.16"/>
<object class="GtkDialog" id="file_properties_dialog">
<property name="can-focus">False</property>
<property name="border-width">6</property>
<property name="title" translatable="yes">File Properties</property>
<property name="modal">True</property>
<property name="window-position">center-on-parent</property>
<property name="default-width">420</property>
<property name="destroy-with-parent">True</property>
<property name="type-hint">dialog</property>
<property name="skip-taskbar-hint">True</property>
<property name="skip-pager-hint">True</property>
<property name="gravity">center</property>
<signal name="response" handler="on_filePropertiesDlg_response" swapped="no"/>
<child internal-child="vbox">
<object class="GtkBox" id="dialog_vbox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">12</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog_action_area">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="layout-style">end</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="can-default">True</property>
<property name="receives-default">False</property>
<property name="use-stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ok_button">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="can-default">True</property>
<property name="receives-default">False</property>
<property name="use-stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack-type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkNotebook" id="notebook">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="border-width">6</property>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="top-padding">6</property>
<property name="bottom-padding">6</property>
<property name="left-padding">12</property>
<child>
<object class="GtkTable" id="general_table">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">4</property>
<property name="n-rows">7</property>
<property name="n-columns">2</property>
<property name="column-spacing">12</property>
<property name="row-spacing">6</property>
<child>
<object class="GtkLabel" id="label_filename">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;File _Name:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="mnemonic-widget">file_name</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkEntry" id="file_name">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label20">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;_Location:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="mnemonic-widget">file_location</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="top-attach">1</property>
<property name="bottom-attach">2</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkEntry" id="file_location">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="top-attach">1</property>
<property name="bottom-attach">2</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_target">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Link _Target:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="mnemonic-widget">file_target</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="top-attach">2</property>
<property name="bottom-attach">3</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkEntry" id="file_target">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="top-attach">2</property>
<property name="bottom-attach">3</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Type:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="top-attach">3</property>
<property name="bottom-attach">4</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="mime_type">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="selectable">True</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="top-attach">3</property>
<property name="bottom-attach">4</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Size:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="top-attach">4</property>
<property name="bottom-attach">5</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="file_size">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="top-attach">4</property>
<property name="bottom-attach">5</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;_Modified:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="top-attach">5</property>
<property name="bottom-attach">6</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;_Accessed:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="top-attach">6</property>
<property name="bottom-attach">7</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkEntry" id="mtime">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="top-attach">5</property>
<property name="bottom-attach">6</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkEntry" id="atime">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="top-attach">6</property>
<property name="bottom-attach">7</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">_Info</property>
<property name="use-underline">True</property>
</object>
<packing>
<property name="tab-fill">False</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="top-padding">6</property>
<property name="bottom-padding">6</property>
<property name="left-padding">12</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkTable" id="table3">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">2</property>
<property name="n-rows">2</property>
<property name="n-columns">2</property>
<property name="column-spacing">12</property>
<property name="row-spacing">6</property>
<child>
<object class="GtkLabel" id="owner_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;_Owner:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="mnemonic-widget">file_owner</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="group_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;_Group:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="mnemonic-widget">file_group</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="top-attach">1</property>
<property name="bottom-attach">2</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkEntry" id="file_owner">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkEntry" id="file_group">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="top-attach">1</property>
<property name="bottom-attach">2</property>
<property name="y-options"/>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHSeparator" id="hseparator1">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">4</property>
<property name="n-rows">3</property>
<property name="n-columns">5</property>
<property name="column-spacing">12</property>
<property name="row-spacing">6</property>
<child>
<object class="GtkLabel" id="label17">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Owner:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label18">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Group:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="top-attach">1</property>
<property name="bottom-attach">2</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkLabel" id="label19">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;Other:&lt;/b&gt;</property>
<property name="use-markup">True</property>
<property name="use-underline">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="top-attach">2</property>
<property name="bottom-attach">3</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="owner_r">
<property name="label" translatable="yes">Read</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="border-width">2</property>
<property name="use-underline">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="group_r">
<property name="label" translatable="yes">Read</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="border-width">2</property>
<property name="use-underline">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="top-attach">1</property>
<property name="bottom-attach">2</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="others_r">
<property name="label" translatable="yes">Read</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="border-width">2</property>
<property name="use-underline">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="right-attach">2</property>
<property name="top-attach">2</property>
<property name="bottom-attach">3</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="owner_w">
<property name="label" translatable="yes">Write</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="border-width">2</property>
<property name="use-underline">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">2</property>
<property name="right-attach">3</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="group_w">
<property name="label" translatable="yes">Write</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="border-width">2</property>
<property name="use-underline">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">2</property>
<property name="right-attach">3</property>
<property name="top-attach">1</property>
<property name="bottom-attach">2</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="others_w">
<property name="label" translatable="yes">Write</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="border-width">2</property>
<property name="use-underline">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">2</property>
<property name="right-attach">3</property>
<property name="top-attach">2</property>
<property name="bottom-attach">3</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="owner_x">
<property name="label" translatable="yes">Execute</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="border-width">2</property>
<property name="use-underline">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">3</property>
<property name="right-attach">4</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="group_x">
<property name="label" translatable="yes">Execute</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="border-width">2</property>
<property name="use-underline">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">3</property>
<property name="right-attach">4</property>
<property name="top-attach">1</property>
<property name="bottom-attach">2</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="others_x">
<property name="label" translatable="yes">Execute</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="border-width">2</property>
<property name="use-underline">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="left-attach">3</property>
<property name="right-attach">4</property>
<property name="top-attach">2</property>
<property name="bottom-attach">3</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options"/>
</packing>
</child>
<child>
<object class="GtkVSeparator" id="vseparator1">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="left-attach">4</property>
<property name="right-attach">5</property>
<property name="bottom-attach">3</property>
<property name="x-options">GTK_FILL</property>
<property name="y-options">GTK_FILL</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">_Permissions</property>
<property name="use-underline">True</property>
</object>
<packing>
<property name="position">1</property>
<property name="tab-fill">False</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">cancel_button</action-widget>
<action-widget response="-5">ok_button</action-widget>
</action-widgets>
</object>
</interface>

View File

@ -0,0 +1,263 @@
# Python imports
import os, threading, subprocess, time
from datetime import datetime
# Gtk imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib, Gio
# Application imports
# NOTE: Threads WILL NOT die with parent's destruction.
def threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
return wrapper
# NOTE: Threads WILL die with parent's destruction.
def daemon_threaded(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
return wrapper
class Manifest:
path: str = os.path.dirname(os.path.realpath(__file__))
name: str = "Properties"
author: str = "ITDominator"
version: str = "0.0.1"
support: str = ""
requests: {} = {
'ui_target': "context_menu",
'pass_fm_events': "true"
}
class Properties:
file_uri: str = None
file_name: str = None
file_location: str = None
file_target: str = None
mime_type: str = None
file_size: str = None
mtime: int = None
atime: int = None
file_owner: str = None
file_group: str = None
chmod_stat: str = None
class Plugin(Manifest):
def __init__(self):
self._GLADE_FILE = f"{self.path}/file_properties.glade"
self._builder = None
self._properties_dialog = None
self._event_system = None
self._event_sleep_time = .5
self._event_message = None
self._file_name = None
self._file_location = None
self._file_target = None
self._mime_type = None
self._file_size = None
self._mtime = None
self._atime = None
self._file_owner = None
self._file_group = None
self._chmod_map: {} = {
"7": "rwx",
"6": "rw",
"5": "rx",
"4": "r",
"3": "wx",
"2": "w",
"1": "x",
"0": ""
}
self._chmod_map_counter: {} = {
"rwx": "7",
"rw": "6",
"rx": "5",
"r": "4",
"wx": "3",
"w": "2",
"x": "1",
"": "0"
}
def get_ui_element(self):
self._builder = Gtk.Builder()
self._builder.add_from_file(self._GLADE_FILE)
self._properties_dialog = self._builder.get_object("file_properties_dialog")
self._file_name = self._builder.get_object("file_name")
self._file_location = self._builder.get_object("file_location")
self._file_target = self._builder.get_object("file_target")
self._mime_type = self._builder.get_object("mime_type")
self._file_size = self._builder.get_object("file_size")
self._mtime = self._builder.get_object("mtime")
self._atime = self._builder.get_object("atime")
self._file_owner = self._builder.get_object("file_owner")
self._file_group = self._builder.get_object("file_group")
button = Gtk.Button(label=self.name)
button.connect("button-release-event", self._show_properties_page)
return button
def set_fm_event_system(self, fm_event_system):
self._event_system = fm_event_system
def run(self):
self._module_event_observer()
@threaded
def _show_properties_page(self, widget=None, eve=None):
self._event_system.push_gui_event([self.name, "get_current_state", ()])
self.wait_for_fm_message()
state = self._event_message
self._event_message = None
GLib.idle_add(self._process_changes, (state))
def _process_changes(self, state):
if len(state.selected_files) == 1:
uri = state.selected_files[0]
path = state.tab.get_current_directory()
properties = self._set_ui_data(uri, path)
response = self._properties_dialog.run()
if response in [Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT]:
self._properties_dialog.hide()
self._update_file(properties)
self._properties_dialog.hide()
def _update_file(self, properties):
chmod_stat = self._get_check_boxes()
if chmod_stat is not properties.chmod_stat:
try:
print("\nNew chmod flags...")
print(f"Old: {''.join(properties.chmod_stat)}")
print(f"New: {chmod_stat}")
# self._guest_fs.chmod(int(chmod_stat), properties.file_uri)
except Exception as e:
print(f"Couldn't chmod\nFile: {properties.file_uri}")
print( repr(e) )
def _set_ui_data(self, uri, path):
properties = Properties()
file_info = Gio.File.new_for_path(uri).query_info(attributes="standard::*,owner::*,time::access,time::changed",
flags=Gio.FileQueryInfoFlags.NONE,
cancellable=None)
is_symlink = file_info.get_attribute_as_string("standard::is-symlink")
properties.file_uri = uri
properties.file_target = file_info.get_attribute_as_string("standard::symlink-target") if is_symlink else ""
properties.file_name = file_info.get_display_name()
properties.file_location = path
properties.mime_type = file_info.get_content_type()
properties.file_size = self._sizeof_fmt(file_info.get_size())
properties.mtime = datetime.fromtimestamp( int(file_info.get_attribute_as_string("time::changed")) ).strftime("%A, %B %d, %Y %I:%M:%S")
properties.atime = datetime.fromtimestamp( int(file_info.get_attribute_as_string("time::access")) ).strftime("%A, %B %d, %Y %I:%M:%S")
properties.file_owner = file_info.get_attribute_as_string("owner::user")
properties.file_group = file_info.get_attribute_as_string("owner::group")
# NOTE: Read = 4, Write = 2, Exec = 1
command = ["stat", "-c", "%a", uri]
with subprocess.Popen(command, stdout=subprocess.PIPE) as proc:
properties.chmod_stat = list(proc.stdout.read().decode("UTF-8").strip())
owner = self._chmod_map[f"{properties.chmod_stat[0]}"]
group = self._chmod_map[f"{properties.chmod_stat[1]}"]
others = self._chmod_map[f"{properties.chmod_stat[2]}"]
self._reset_check_boxes()
self._set_check_boxes([["owner", owner], ["group", group], ["others", others]])
self._file_name.set_text(properties.file_name)
self._file_location.set_text(properties.file_location)
self._file_target.set_text(properties.file_target)
self._mime_type.set_label(properties.mime_type)
self._file_size.set_label(properties.file_size)
self._mtime.set_text(properties.mtime)
self._atime.set_text(properties.atime)
self._file_owner.set_text(properties.file_owner)
self._file_group.set_text(properties.file_group)
return properties
def _get_check_boxes(self):
perms = [[], [], []]
for i, target in enumerate(["owner", "group", "others"]):
for type in ["r", "w", "x"]:
is_active = self._builder.get_object(f"{target}_{type}").get_active()
if is_active:
perms[i].append(type)
digits = []
for perm in perms:
digits.append(self._chmod_map_counter[ ''.join(perm) ])
return ''.join(digits)
def _set_check_boxes(self, targets):
for name, target in targets:
for type in list(target):
obj = f"{name}_{type}"
self._builder.get_object(obj).set_active(True)
def _reset_check_boxes(self):
for target in ["owner", "group", "others"]:
for type in ["r", "w", "x"]:
self._builder.get_object(f"{target}_{type}").set_active(False)
def _sizeof_fmt(self, num, suffix="B"):
for unit in ["", "K", "M", "G", "T", "Pi", "Ei", "Zi"]:
if abs(num) < 1024.0:
return f"{num:3.1f} {unit}{suffix}"
num /= 1024.0
return f"{num:.1f} Yi{suffix}"
def wait_for_fm_message(self):
while not self._event_message:
pass
@daemon_threaded
def _module_event_observer(self):
while True:
time.sleep(self._event_sleep_time)
event = self._event_system.read_module_event()
if event:
try:
if event[0] == self.name:
target_id, method_target, data = self._event_system.consume_module_event()
if not method_target:
self._event_message = data
else:
method = getattr(self.__class__, f"{method_target}")
if data:
data = method(*(self, *data))
else:
method(*(self,))
except Exception as e:
print(repr(e))

View File

@ -25,12 +25,12 @@ def daemon_threaded(fn):
class Manifest: class Manifest:
path: str = os.path.dirname(os.path.realpath(__file__)) path: str = os.path.dirname(os.path.realpath(__file__))
name: str = "Example Plugin" name: str = "Example Plugin"
author: str = "John Doe" author: str = "John Doe"
version: str = "0.0.1" version: str = "0.0.1"
support: str = "" support: str = ""
permissions: {} = { requests: {} = {
'ui_target': "plugin_control_list", 'ui_target': "plugin_control_list",
'pass_fm_events': "true", 'pass_fm_events': "true",
'bind_keys': [f"{name}||send_message:<Control>f"] 'bind_keys': [f"{name}||send_message:<Control>f"]
@ -39,7 +39,7 @@ class Manifest:
class Plugin(Manifest): class Plugin(Manifest):
def __init__(self): def __init__(self):
self._event_system = event_system self._event_system = None
self._event_sleep_time = .5 self._event_sleep_time = .5
self._event_message = None self._event_message = None
@ -50,7 +50,7 @@ class Plugin(Manifest):
return button return button
def set_fm_event_system(self, fm_event_system): def set_fm_event_system(self, fm_event_system):
self.event_system = fm_event_system self._event_system = fm_event_system
def run(self): def run(self):
self._module_event_observer() self._module_event_observer()
@ -62,6 +62,10 @@ class Plugin(Manifest):
self._event_system.push_gui_event([self.name, "display_message", ("warning", message, None)]) self._event_system.push_gui_event([self.name, "display_message", ("warning", message, None)])
def wait_for_fm_message(self):
while not self._event_message:
pass
@daemon_threaded @daemon_threaded
def _module_event_observer(self): def _module_event_observer(self):
while True: while True:
@ -81,5 +85,4 @@ class Plugin(Manifest):
else: else:
method(*(self,)) method(*(self,))
except Exception as e: except Exception as e:
print("ewww here")
print(repr(e)) print(repr(e))

View File

@ -25,12 +25,12 @@ def daemon_threaded(fn):
class Manifest: class Manifest:
path: str = os.path.dirname(os.path.realpath(__file__)) path: str = os.path.dirname(os.path.realpath(__file__))
name: str = "Youtube Download" name: str = "Youtube Download"
author: str = "ITDominator" author: str = "ITDominator"
version: str = "0.0.1" version: str = "0.0.1"
support: str = "" support: str = ""
permissions: {} = { requests: {} = {
'ui_target': "plugin_control_list", 'ui_target': "plugin_control_list",
'pass_fm_events': "true" 'pass_fm_events': "true"
@ -39,9 +39,9 @@ class Manifest:
class Plugin(Manifest): class Plugin(Manifest):
def __init__(self): def __init__(self):
self._fm_event_system = None self._event_system = None
self._event_sleep_time = .5 self._event_sleep_time = .5
self._fm_event_message = None self._event_message = None
def get_ui_element(self): def get_ui_element(self):
@ -50,24 +50,38 @@ class Plugin(Manifest):
return button return button
def set_fm_event_system(self, fm_event_system): def set_fm_event_system(self, fm_event_system):
self._fm_event_system = fm_event_system self._event_system = fm_event_system
def run(self): def run(self):
self._module_event_observer() self._module_event_observer()
@threaded
def _do_download(self, widget=None, eve=None):
self._event_system.push_gui_event([self.name, "get_current_state", ()])
self.wait_for_fm_message()
state = self._event_message
subprocess.Popen([f'{self.path}/download.sh' , state.tab.get_current_directory()])
self._event_message = None
def wait_for_fm_message(self):
while not self._event_message:
pass
@daemon_threaded @daemon_threaded
def _module_event_observer(self): def _module_event_observer(self):
while True: while True:
time.sleep(self._event_sleep_time) time.sleep(self._event_sleep_time)
event = self._fm_event_system.read_module_event() event = self._event_system.read_module_event()
if event: if event:
try: try:
if event[0] == self.name: if event[0] == self.name:
target_id, method_target, data = self._fm_event_system.consume_module_event() target_id, method_target, data = self._event_system.consume_module_event()
if not method_target: if not method_target:
self._fm_event_message = data self._event_message = data
else: else:
method = getattr(self.__class__, f"{method_target}") method = getattr(self.__class__, f"{method_target}")
if data: if data:
@ -76,14 +90,3 @@ class Plugin(Manifest):
method(*(self,)) method(*(self,))
except Exception as e: except Exception as e:
print(repr(e)) print(repr(e))
@threaded
def _do_download(self, widget=None, eve=None):
self._fm_event_system.push_gui_event([self.name, "get_current_state", ()])
while not self._fm_event_message:
pass
state = self._fm_event_message
subprocess.Popen([f'{self.path}/download.sh' , state.tab.get_current_directory()])
self._fm_event_message = None

View File

@ -19,6 +19,9 @@ class State:
tab: type = None tab: type = None
icon_grid: gi.overrides.Gtk.IconView = None icon_grid: gi.overrides.Gtk.IconView = None
store: gi.overrides.Gtk.ListStore = None store: gi.overrides.Gtk.ListStore = None
selected_files: [] = None
to_copy_files: [] = None
to_cut_files: [] = None
class Controller_Data: class Controller_Data:
@ -138,6 +141,18 @@ class Controller_Data:
state.icon_grid = self.builder.get_object(f"{state.wid}|{state.tid}|icon_grid") state.icon_grid = self.builder.get_object(f"{state.wid}|{state.tid}|icon_grid")
state.store = state.icon_grid.get_model() state.store = state.icon_grid.get_model()
selected_files = state.icon_grid.get_selected_items()
# if self.selected_files:
if selected_files:
state.selected_files = self.format_to_uris(state.store, state.wid, state.tid, selected_files, True)
# if self.to_copy_files:
# state.to_copy_files = self.format_to_uris(state.store, state.wid, state.tid, self.to_copy_files, True)
#
# if self.to_cut_files:
# state.to_cut_files = self.format_to_uris(state.store, state.wid, state.tid, self.to_cut_files, True)
return state return state

View File

@ -16,7 +16,7 @@ class Plugin:
author: str = None author: str = None
version: str = None version: str = None
support: str = None support: str = None
permissions:{} = None requests:{} = None
reference: type = None reference: type = None
@ -53,72 +53,76 @@ class Plugins:
print(f"Loading plugins...") print(f"Loading plugins...")
parent_path = os.getcwd() parent_path = os.getcwd()
for file in os.listdir(self._plugins_path): for path, folder in [[join(self._plugins_path, item), item] if os.path.isdir(join(self._plugins_path, item)) else None for item in os.listdir(self._plugins_path)]:
try: try:
path = join(self._plugins_path, file) target = join(path, "plugin.py")
if isdir(path): if not os.path.exists(target):
module = self.load_plugin_module(path, file) raise Exception("Invalid Plugin Structure: Plugin doesn't have 'plugin.py'. Aboarting load...")
plugin = self.collect_info(module, path)
loading_data = self.parse_permissions(plugin)
self.execute_plugin(module, plugin, loading_data) module = self.load_plugin_module(path, folder, target)
plugin = self.collect_info(module, path)
loading_data = self.parse_requests(plugin)
self.execute_plugin(module, plugin, loading_data)
except Exception as e: except Exception as e:
print("Malformed plugin! Not loading!") print(f"Malformed Plugin: Not loading -->: '{folder}' !")
traceback.print_exc() traceback.print_exc()
# if debug:
# traceback.print_exc()
os.chdir(parent_path) os.chdir(parent_path)
def load_plugin_module(self, path, file): def load_plugin_module(self, path, folder, target):
os.chdir(path) os.chdir(path)
sys.path.insert(0, path) sys.path.insert(0, path)
spec = importlib.util.spec_from_file_location(file, join(path, "plugin.py")) spec = importlib.util.spec_from_file_location(folder, target)
module = importlib.util.module_from_spec(spec) module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module) spec.loader.exec_module(module)
return module return module
def collect_info(self, module, path) -> Plugin: def collect_info(self, module, path) -> Plugin:
plugin = Plugin() plugin = Plugin()
plugin.path = module.Manifest.path plugin.path = module.Manifest.path
plugin.name = module.Manifest.name plugin.name = module.Manifest.name
plugin.author = module.Manifest.author plugin.author = module.Manifest.author
plugin.version = module.Manifest.version plugin.version = module.Manifest.version
plugin.support = module.Manifest.support plugin.support = module.Manifest.support
plugin.permissions = module.Manifest.permissions plugin.requests = module.Manifest.requests
return plugin return plugin
def parse_permissions(self, plugin): def parse_requests(self, plugin):
loading_data = {} loading_data = {}
permissions = plugin.permissions requests = plugin.requests
keys = permissions.keys() keys = requests.keys()
if "ui_target" in keys: if "ui_target" in keys:
if permissions["ui_target"] in [ if requests["ui_target"] in [
"none", "other", "main_Window", "main_menu_bar", "path_menu_bar", "plugin_control_list", "none", "other", "main_Window", "main_menu_bar", "path_menu_bar", "plugin_control_list",
"context_menu", "window_1", "window_2", "window_3", "window_4" "context_menu", "window_1", "window_2", "window_3", "window_4"
]: ]:
if permissions["ui_target"] == "other": if requests["ui_target"] == "other":
if "ui_target_id" in keys: if "ui_target_id" in keys:
loading_data["ui_target"] = self._builder.get_object(permissions["ui_target_id"]) loading_data["ui_target"] = self._builder.get_object(requests["ui_target_id"])
if loading_data["ui_target"] == None: if loading_data["ui_target"] == None:
raise Exception('Invalid "ui_target_id" given in permissions. Must have one if setting "ui_target" to "other"...') raise Exception('Invalid "ui_target_id" given in requests. Must have one if setting "ui_target" to "other"...')
else: else:
raise Exception('Invalid "ui_target_id" given in permissions. Must have one if setting "ui_target" to "other"...') raise Exception('Invalid "ui_target_id" given in requests. Must have one if setting "ui_target" to "other"...')
else: else:
loading_data["ui_target"] = self._builder.get_object(permissions["ui_target"]) loading_data["ui_target"] = self._builder.get_object(requests["ui_target"])
else: else:
raise Exception('Unknown "ui_target" given in permissions.') raise Exception('Unknown "ui_target" given in requests.')
if "pass_fm_events" in keys: if "pass_fm_events" in keys:
if permissions["pass_fm_events"] in ["true"]: if requests["pass_fm_events"] in ["true"]:
loading_data["pass_fm_events"] = True loading_data["pass_fm_events"] = True
if "bind_keys" in keys: if "bind_keys" in keys:
if isinstance(permissions["bind_keys"], list): if isinstance(requests["bind_keys"], list):
loading_data["bind_keys"] = permissions["bind_keys"] loading_data["bind_keys"] = requests["bind_keys"]
return loading_data return loading_data