diff options
author | Matthias Baumgartner <dev@igsor.net> | 2023-01-29 11:31:16 +0100 |
---|---|---|
committer | Matthias Baumgartner <dev@igsor.net> | 2023-01-29 11:31:16 +0100 |
commit | 4d0ce7fb62eaad3a1f705ec3c77744e3ebc96a9e (patch) | |
tree | dbaf156f663de415bbcb9298d45b45d021d23612 | |
parent | d531555fe3483fac7676aa634f3787e8eab9b67f (diff) | |
download | tagit-4d0ce7fb62eaad3a1f705ec3c77744e3ebc96a9e.tar.gz tagit-4d0ce7fb62eaad3a1f705ec3c77744e3ebc96a9e.tar.bz2 tagit-4d0ce7fb62eaad3a1f705ec3c77744e3ebc96a9e.zip |
session actions port
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | tagit/actions/__init__.py | 8 | ||||
-rw-r--r-- | tagit/actions/session.kv | 7 | ||||
-rw-r--r-- | tagit/actions/session.py | 56 | ||||
-rw-r--r-- | tagit/apps/port-config.yaml | 4 | ||||
-rw-r--r-- | tagit/assets/icons/scalable/session/open.svg | 180 | ||||
-rw-r--r-- | tagit/dialogues/__init__.py | 8 | ||||
-rw-r--r-- | tagit/dialogues/file_picker.py | 39 | ||||
-rw-r--r-- | tagit/dialogues/path_picker.kv | 27 | ||||
-rw-r--r-- | tagit/dialogues/path_picker.py | 41 | ||||
-rw-r--r-- | tagit/widgets/session.py | 21 |
11 files changed, 374 insertions, 18 deletions
@@ -38,6 +38,7 @@ tagit/assets/icons/kivy/grouping* tagit/assets/icons/kivy/misc* tagit/assets/icons/kivy/planes* tagit/assets/icons/kivy/search* +tagit/assets/icons/kivy/session* tagit/assets/icons/kivy/tagging* ## EOF ## diff --git a/tagit/actions/__init__.py b/tagit/actions/__init__.py index 7144e44..fa2bed0 100644 --- a/tagit/actions/__init__.py +++ b/tagit/actions/__init__.py @@ -18,7 +18,7 @@ from . import misc #from . import objects from . import planes from . import search -#from . import session +from . import session from . import tagging # exports @@ -104,11 +104,7 @@ class ActionBuilder(BuilderBase): #'SortKey': search.SortKey, 'SortOrder': search.SortOrder, ## session - #'LoadSession': session.LoadSession, - #'CreateSession': session.CreateSession, - #'CreateTempSession': session.CreateTempSession, - #'ReloadSession': session.ReloadSession, - #'CloseSessionAndExit': session.CloseSessionAndExit, + 'LoadSession': session.LoadSession, } ## EOF ## diff --git a/tagit/actions/session.kv b/tagit/actions/session.kv new file mode 100644 index 0000000..21807b2 --- /dev/null +++ b/tagit/actions/session.kv @@ -0,0 +1,7 @@ +#:import resource_find kivy.resources.resource_find + +<LoadSession>: + source: resource_find('atlas://session/open') + tooltip: 'Load a session' + +## EOF ## diff --git a/tagit/actions/session.py b/tagit/actions/session.py new file mode 100644 index 0000000..3c5ad39 --- /dev/null +++ b/tagit/actions/session.py @@ -0,0 +1,56 @@ +""" + +Part of the tagit module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# standard imports +import os + +# kivy imports +from kivy.lang import Builder +import kivy.properties as kp + +# tagit imports +from tagit import config, dialogues +from tagit.config.loader import load_settings + +# inner-module imports +from .action import Action + +# exports +__all__ = [] + + +## code ## + +# load kv +Builder.load_file(os.path.join(os.path.dirname(__file__), 'session.kv')) + +# classes +class LoadSession(Action): + """Load a session from a project file.""" + text = kp.StringProperty('Load') + + def apply(self): + """Open a file load dialogue to select a session file.""" + dlg = dialogues.FilePicker(title='Select a session file to load') + dlg.bind(on_ok=self.load_from_path) + dlg.open() + + def load_from_path(self, wx): + """Load a session from *path*.""" + with self.root.session as session: + try: + if not os.path.exists(wx.path) or not os.path.isfile(wx.path): + raise FileNotFoundError(wx.path) + + # load config from path + cfg = load_settings(wx.path, verbose=self.cfg('session', 'verbose')) + session.load(cfg) + + except Exception as e: + dialogues.Error(text=f'The file cannot be loaded ({e})').open() + + +## EOF ## diff --git a/tagit/apps/port-config.yaml b/tagit/apps/port-config.yaml index 6b0b06d..c4d47dd 100644 --- a/tagit/apps/port-config.yaml +++ b/tagit/apps/port-config.yaml @@ -87,8 +87,8 @@ ui: - AddToGroup # - RepresentGroup # - RemoveFromGroup - # root: - # - CloseSessionAndExit + root: + - LoadSession # search: # - ShowSelected # - RemoveSelected diff --git a/tagit/assets/icons/scalable/session/open.svg b/tagit/assets/icons/scalable/session/open.svg new file mode 100644 index 0000000..0b2d29c --- /dev/null +++ b/tagit/assets/icons/scalable/session/open.svg @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="100mm" + height="100mm" + id="svg2" + version="1.1" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="open.svg" + inkscape:export-filename="../../kivy/session/open.png" + inkscape:export-xdpi="7.6199999" + inkscape:export-ydpi="7.6199999"> + <defs + id="defs4"> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath868"> + <rect + style="opacity:1;fill:#c8c8c8;fill-opacity:1;stroke:none;stroke-width:40;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke" + id="rect870" + width="422.74884" + height="230.81985" + x="144.88318" + y="556.44757" /> + </clipPath> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.979899" + inkscape:cx="126.58161" + inkscape:cy="190.628" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + showguides="true" + inkscape:guide-bbox="true" + inkscape:snap-global="true" + inkscape:snap-bbox="true" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1920" + inkscape:window-height="1031" + inkscape:window-x="0" + inkscape:window-y="25" + inkscape:window-maximized="1" + inkscape:pagecheckerboard="true" + units="mm" + inkscape:bbox-paths="true" + inkscape:bbox-nodes="true" + inkscape:snap-bbox-edge-midpoints="true" + inkscape:snap-bbox-midpoints="true" + inkscape:object-paths="true" + inkscape:snap-intersection-paths="true" + inkscape:snap-smooth-nodes="true" + inkscape:snap-midpoints="true" + inkscape:snap-object-midpoints="true" + inkscape:snap-center="true" + inkscape:snap-text-baseline="true" + inkscape:snap-page="true" + inkscape:lockguides="false"> + <sodipodi:guide + orientation="0,1" + position="13.637059,643.40404" + id="guide3788" + inkscape:locked="false" /> + <sodipodi:guide + position="188.97638,188.97638" + orientation="0,1" + id="guide1099" + inkscape:locked="false" + inkscape:label="" + inkscape:color="rgb(0,0,255)" /> + <sodipodi:guide + position="188.97638,188.97638" + orientation="1,0" + id="guide1101" + inkscape:locked="false" + inkscape:label="" + inkscape:color="rgb(0,0,255)" /> + <sodipodi:guide + position="233.588,370" + orientation="1,0" + id="guide1107" + inkscape:locked="false" + inkscape:label="" + inkscape:color="rgb(0,0,255)" /> + <sodipodi:guide + position="144.36496,311.42857" + orientation="1,0" + id="guide1109" + inkscape:locked="false" + inkscape:label="" + inkscape:color="rgb(0,0,255)" /> + <sodipodi:guide + position="-77.142857,144.36496" + orientation="0,1" + id="guide1111" + inkscape:locked="false" + inkscape:label="" + inkscape:color="rgb(0,0,255)" /> + <sodipodi:guide + position="5.000315,233.58779" + orientation="0,1" + id="guide1113" + inkscape:locked="false" + inkscape:label="" + inkscape:color="rgb(0,0,255)" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-167.28122,-322.85977)"> + <rect + style="fill:none;stroke:#c8c8c8;stroke-width:72.52050018;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect2985" + width="299.20886" + height="197.09306" + x="206.65317" + y="470.40216" + clip-path="url(#clipPath868)" + transform="matrix(1.0167417,0,0,0.98002182,-5.9643702,11.116803)" /> + <g + id="g840" + transform="matrix(0.51843117,0,0,0.4508665,223.54494,300.20217)"> + <rect + y="292.88489" + x="155.32295" + height="368.57141" + width="202.85715" + id="rect4389" + style="fill:#c8c8c8;fill-opacity:1;stroke:none" /> + <path + transform="matrix(0.57204501,-0.03460321,0.03460321,0.57204501,160.61503,278.02467)" + inkscape:transform-center-y="-50.478468" + inkscape:transform-center-x="-0.051265028" + d="M 460.00001,209.50504 155.15754,191.22021 -149.68493,172.93537 18.571437,-81.923531 186.8278,-336.78244 323.4139,-63.638699 Z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="false" + sodipodi:arg2="1.6307058" + sodipodi:arg1="0.58350825" + sodipodi:r2="176.3172" + sodipodi:r1="352.6344" + sodipodi:cy="15.219325" + sodipodi:cx="165.71429" + sodipodi:sides="3" + id="path4391" + style="fill:#c8c8c8;fill-opacity:1;stroke:#c8c8c8;stroke-width:100;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + sodipodi:type="star" /> + </g> + </g> +</svg> diff --git a/tagit/dialogues/__init__.py b/tagit/dialogues/__init__.py index a467699..3647bf0 100644 --- a/tagit/dialogues/__init__.py +++ b/tagit/dialogues/__init__.py @@ -23,11 +23,11 @@ from .console import Console #from .dir_picker import DirPicker from .error import Error #from .file_creator import FileCreator -#from .file_picker import FilePicker +from .file_picker import FilePicker from .message import Message from .numeric_input import NumericInput #from .path_creator import PathCreator -#from .path_picker import PathPicker +from .path_picker import PathPicker #from .project import Project from .simple_input import SimpleInput from .stoken import TokenEdit @@ -40,11 +40,11 @@ __all__: typing.Sequence[str] = ( #'DirPicker', 'Error', #'FileCreator', - #'FilePicker', + 'FilePicker', 'Message', 'NumericInput', #'PathCreator', - #'PathPicker', + 'PathPicker', #'Project', 'SimpleInput', 'TokenEdit', diff --git a/tagit/dialogues/file_picker.py b/tagit/dialogues/file_picker.py new file mode 100644 index 0000000..283adb6 --- /dev/null +++ b/tagit/dialogues/file_picker.py @@ -0,0 +1,39 @@ +"""Dialogue to pick a file. + +Part of the tagit module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# standard imports +import os + +# kivy imports +from kivy.lang import Builder + +# inner-module imports +from .path_picker import PathPicker +from .error import Error + +# exports +__all__ = ('FilePicker', ) + + +## code ## + +# load kv +Builder.load_string(''' +<FilePicker>: + dirselect: False + title: 'Please select a file' +''') + +# classes +class FilePicker(PathPicker): + """Dialogue with a file browser to select a file.""" + def ok(self): + if not os.path.exists(self.path) or not os.path.isfile(self.path): + Error(text='Please select a file').open() + else: + super(FilePicker, self).ok() + +## EOF ## diff --git a/tagit/dialogues/path_picker.kv b/tagit/dialogues/path_picker.kv new file mode 100644 index 0000000..1837b80 --- /dev/null +++ b/tagit/dialogues/path_picker.kv @@ -0,0 +1,27 @@ +#:import join os.path.join +#:import pwd os.path.curdir + +<PathPicker>: + path: '' + title: 'Please select a file or directory' + filters: [] + dirselect: True + + DialogueContentTitle: + title: root.title + size_hint_y: 0.8 + + FileChooserListView: + text_size: self.width - dp(16), None + halign: 'center' + dirselect: root.dirselect + path: pwd + filters: root.filters + + on_selection: root.path = join(self.path, self.selection[0]); buttons.ok_enabled = True + + DialogueButtons_Two: + id: buttons + ok_enabled: False + +## EOF ## diff --git a/tagit/dialogues/path_picker.py b/tagit/dialogues/path_picker.py new file mode 100644 index 0000000..25bbf32 --- /dev/null +++ b/tagit/dialogues/path_picker.py @@ -0,0 +1,41 @@ +"""Dialogue to pick a file or directory. + +Part of the tagit module. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# standard imports +import os + +# kivy imports +from kivy.lang import Builder +import kivy.properties as kp + +# inner-module imports +from .dialogue import Dialogue +from .error import Error + +# exports +__all__ = ('PathPicker', ) + + +## code ## + +# load kv +Builder.load_file(os.path.join(os.path.dirname(__file__), 'path_picker.kv')) + +# classes +class PathPicker(Dialogue): + """Dialogue with a file browser to select a file or directory.""" + + title = kp.StringProperty('') + path = kp.StringProperty('') + filters = kp.ListProperty() + + def ok(self): + if not os.path.exists(self.path): + Error(text='Please select a file or directory').open() + else: + super(PathPicker, self).ok() + +## EOF ## diff --git a/tagit/widgets/session.py b/tagit/widgets/session.py index f45ab35..e97a688 100644 --- a/tagit/widgets/session.py +++ b/tagit/widgets/session.py @@ -5,7 +5,7 @@ A copy of the license is provided with the project. Author: Matthias Baumgartner, 2022 """ # standard imports -from threading import current_thread +import os import typing # kivy imports @@ -16,8 +16,7 @@ import kivy.properties as kp # tagit imports from tagit import parsing from tagit.config.loader import load_settings -#from tagit.storage.broker import Broker # FIXME: mb/port -#from tagit.storage.loader import load_broker, load_log # FIXME: mb/port +from tagit.utils import bsfs # exports __all__: typing.Sequence[str] = ( @@ -63,10 +62,20 @@ class Session(Widget): def load(self, cfg): """Load the session from configuration *cfg*.""" - self.cfg = cfg + #self.log = load_log(cfg) # FIXME: mb/port # initialize storages from config - self.log = load_log(cfg) - self.storage = load_broker(cfg) + # open BSFS storage + store = bsfs.Open(cfg('session', 'bsfs')) + # check storage schema + # FIXME: how to properly load the required schema? + with open(os.path.join(os.path.dirname(__file__), '..', 'apps', 'port-schema.nt'), 'rt') as ifile: + required_schema = bsfs.schema.from_string(ifile.read()) + # FIXME: Since the store isn't persistent, we migrate to the required one here. + #if not required_schema <= store.schema: + # raise Exception('') + store.migrate(required_schema) + # replace current with new storage + self.storage = store def update_settings_key(self, key, value): # change setting |