Commit 235ce5ba authored by Roman Alifanov's avatar Roman Alifanov

init FileChooser widget

parent 6ca987db
...@@ -39,6 +39,20 @@ ...@@ -39,6 +39,20 @@
gtype: string gtype: string
backend: gsettings backend: gsettings
key: org.gnome.desktop.background.picture-options key: org.gnome.desktop.background.picture-options
- name: Wallpaper
type: file
gtype: string
backend: gsettings
key: org.gnome.desktop.background.picture-uri
map:
extensions: ["*.png", "*.jpeg", "*.jpg", "*.svg", "*.webp"]
- name: Wallpaper (dark)
type: file
gtype: string
backend: gsettings
key: org.gnome.desktop.background.picture-uri-dark
map:
extensions: [ "*.png", "*.jpeg", "*.jpg", "*.svg", "*.webp" ]
- name: "Clock" - name: "Clock"
weight: 10 weight: 10
page: "Date & Time" page: "Date & Time"
...@@ -133,3 +147,83 @@ ...@@ -133,3 +147,83 @@
lower: 0 lower: 0
step: 1 step: 1
digits: 0 digits: 0
- name: "Main"
weight: 0
page: "Dirs"
settings:
- name: Templates
type: file
gtype: s
backend: file
key: XDG_TEMPLATES_DIR
help: Select templates folder
params:
file_path: "~/.config/user-dirs.dirs"
map:
extensions: folder
- name: Public Share
type: file
gtype: s
backend: file
key: XDG_PUBLICSHARE_DIR
help: Select public share folder
params:
file_path: "~/.config/user-dirs.dirs"
map:
extensions: folder
- name: Documents
type: file
gtype: s
backend: file
key: XDG_DOCUMENTS_DIR
help: Select documents folder
params:
file_path: "~/.config/user-dirs.dirs"
map:
extensions: folder
- name: Music
type: file
gtype: s
backend: file
key: XDG_MUSIC_DIR
help: Select music folder
params:
file_path: "~/.config/user-dirs.dirs"
map:
extensions: folder
- name: Pictures
type: file
gtype: s
backend: file
key: XDG_PICTURES_DIR
help: Select pictures folder
params:
file_path: "~/.config/user-dirs.dirs"
map:
extensions: folder
- name: Videos
type: file
gtype: s
backend: file
key: XDG_VIDEOS_DIR
help: Select videos folder
params:
file_path: "~/.config/user-dirs.dirs"
map:
extensions: folder
- name: Downloads
type: file
gtype: s
backend: file
key: XDG_DOWNLOAD_DIR
help: Select downloads folder
params:
file_path: "~/.config/user-dirs.dirs"
map:
extensions: folder
\ No newline at end of file
from gi.repository import Adw, Gtk
from gi.repository import Gio
from .BaseWidget import BaseWidget
class FileChooser(BaseWidget):
def create_row(self):
self.value_separated = False
self.multiple_mode = self.setting.map.get('multiple', False)
self.folder_mode = 'folder' in self.setting.map.get('extensions', [])
row = Adw.ActionRow(
title=self.setting.name,
subtitle=self.setting.help,
subtitle_selectable=True
)
control_box = Gtk.Box(spacing=6, margin_end=12)
if not self.multiple_mode and not self.folder_mode:
self.entry = Gtk.Entry(
placeholder_text="Enter path or click to browse",
hexpand=True,
valign=Gtk.Align.CENTER,
halign=Gtk.Align.END,
)
self.entry.connect("changed", self._on_entry_changed)
control_box.append(self.entry)
else:
self.info_label = Gtk.Label(
label="No selection" if self.folder_mode else "No files selected",
valign=Gtk.Align.CENTER,
css_classes=["dim-label"]
)
control_box.append(self.info_label)
self.select_button = Gtk.Button.new_from_icon_name(
icon_name="folder-open-symbolic"
)
self.select_button.set_valign(Gtk.Align.CENTER)
self.select_button.connect("clicked", self._on_button_clicked)
control_box.append(self.select_button)
row.add_suffix(control_box)
self._update_display()
return row
def _on_button_clicked(self, button):
dialog = Gtk.FileDialog()
# Настройка фильтров
if not self.folder_mode and 'extensions' in self.setting.map:
filters = self._create_file_filters()
if filters.get_n_items() > 0:
dialog.set_filters(filters)
dialog.set_default_filter(filters.get_item(0))
# Установка начальной директории
current = self.setting._get_backend_value()
if current:
try:
current_file = Gio.File.new_for_path(current)
parent = current_file.get_parent() if not self.folder_mode else current_file
dialog.set_initial_folder(parent)
except Exception as e:
print(f"Error setting initial folder: {e}")
# Выбор метода открытия
try:
if self.folder_mode:
dialog.select_folder(
parent=button.get_root(),
callback=self._on_folder_selected
)
elif self.multiple_mode:
dialog.open_multiple(
parent=button.get_root(),
callback=self._on_files_selected
)
else:
dialog.open(
parent=button.get_root(),
callback=self._on_file_selected
)
except Exception as e:
print(f"File dialog error: {e}")
def _create_file_filters(self):
filters = Gio.ListStore.new(Gtk.FileFilter)
patterns = [p for p in self.setting.map.get('extensions', []) if p != 'folder']
if patterns:
file_filter = Gtk.FileFilter()
file_filter.set_name("Supported files")
for pattern in patterns:
if pattern.startswith('.'):
file_filter.add_suffix(pattern[1:])
else:
file_filter.add_pattern(pattern)
filters.append(file_filter)
return filters
def _on_file_selected(self, dialog, result):
try:
file = dialog.open_finish(result)
if file:
self.setting._set_backend_value(file.get_path() if self.value_separated is False
else f"file://{file.get_path()}")
self._update_display()
except Exception as e:
print(f"File selection error: {e}")
def _on_files_selected(self, dialog, result):
try:
file_list = dialog.open_multiple_finish(result)
if file_list:
paths = [f.get_path() for f in file_list]
self.setting._set_backend_value(paths)
self._update_display()
except Exception as e:
print(f"Multiple files selection error: {e}")
def _on_folder_selected(self, dialog, result):
try:
folder = dialog.select_folder_finish(result)
if folder:
self.setting._set_backend_value(folder.get_path())
self._update_display()
except Exception as e:
print(f"Folder selection error: {e}")
def _update_display(self):
current = self.setting._get_backend_value()
if current.startswith("file://"):
current = current[7:]
self.value_separated = True
if self.folder_mode:
self._update_folder_display(current)
elif self.multiple_mode:
self._update_multiple_files_display(current)
else:
self._update_single_file_display(current)
def _update_folder_display(self, current):
if current:
folder = Gio.File.new_for_path(current)
self.info_label.set_label(folder.get_basename() or current)
else:
self.info_label.set_label("No folder selected")
def _update_multiple_files_display(self, current):
count = len(current) if current else 0
self.info_label.set_label(f"{count} files selected" if count else "No files selected")
def _update_single_file_display(self, current):
self.entry.set_text(current or "")
if current:
file = Gio.File.new_for_path(current)
self.entry.set_tooltip_text(file.get_parse_name())
else:
self.entry.set_tooltip_text(None)
def _on_entry_changed(self, entry):
if (not self.folder_mode and
not self.multiple_mode and
not self.setting._get_backend() is not None):
path = entry.get_text().strip()
self.setting._set_backend_value(path if self.value_separated is False
else f"file://{path}")
\ No newline at end of file
...@@ -3,10 +3,11 @@ from .ChoiceWidget import ChoiceWidget ...@@ -3,10 +3,11 @@ from .ChoiceWidget import ChoiceWidget
from .RadioChoiceWidget import RadioChoiceWidget from .RadioChoiceWidget import RadioChoiceWidget
from .EntryWidget import EntryWidget from .EntryWidget import EntryWidget
from .NumStepper import NumStepper from .NumStepper import NumStepper
from .FileChooser import FileChooser
class WidgetFactory: class WidgetFactory:
widget_map = { widget_map = {
'file': FileChooser,
'choice': ChoiceWidget, 'choice': ChoiceWidget,
'choice_radio': RadioChoiceWidget, 'choice_radio': RadioChoiceWidget,
'boolean': BooleanWidget, 'boolean': BooleanWidget,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment