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

init FileChooser widget

parent 6ca987db
......@@ -39,6 +39,20 @@
gtype: string
backend: gsettings
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"
weight: 10
page: "Date & Time"
......@@ -133,3 +147,83 @@
lower: 0
step: 1
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
from .RadioChoiceWidget import RadioChoiceWidget
from .EntryWidget import EntryWidget
from .NumStepper import NumStepper
from .FileChooser import FileChooser
class WidgetFactory:
widget_map = {
'file': FileChooser,
'choice': ChoiceWidget,
'choice_radio': RadioChoiceWidget,
'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