pomera-ai-commander 1.1.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +105 -680
- package/bin/pomera-ai-commander.js +62 -62
- package/core/__init__.py +65 -65
- package/core/app_context.py +482 -482
- package/core/async_text_processor.py +421 -421
- package/core/backup_manager.py +655 -655
- package/core/backup_recovery_manager.py +1199 -1033
- package/core/content_hash_cache.py +508 -508
- package/core/context_menu.py +313 -313
- package/core/data_directory.py +549 -0
- package/core/data_validator.py +1066 -1066
- package/core/database_connection_manager.py +744 -744
- package/core/database_curl_settings_manager.py +608 -608
- package/core/database_promera_ai_settings_manager.py +446 -446
- package/core/database_schema.py +411 -411
- package/core/database_schema_manager.py +395 -395
- package/core/database_settings_manager.py +1507 -1507
- package/core/database_settings_manager_interface.py +456 -456
- package/core/dialog_manager.py +734 -734
- package/core/diff_utils.py +239 -0
- package/core/efficient_line_numbers.py +540 -510
- package/core/error_handler.py +746 -746
- package/core/error_service.py +431 -431
- package/core/event_consolidator.py +511 -511
- package/core/mcp/__init__.py +43 -43
- package/core/mcp/find_replace_diff.py +334 -0
- package/core/mcp/protocol.py +288 -288
- package/core/mcp/schema.py +251 -251
- package/core/mcp/server_stdio.py +299 -299
- package/core/mcp/tool_registry.py +2699 -2345
- package/core/memento.py +275 -0
- package/core/memory_efficient_text_widget.py +711 -711
- package/core/migration_manager.py +914 -914
- package/core/migration_test_suite.py +1085 -1085
- package/core/migration_validator.py +1143 -1143
- package/core/optimized_find_replace.py +714 -714
- package/core/optimized_pattern_engine.py +424 -424
- package/core/optimized_search_highlighter.py +552 -552
- package/core/performance_monitor.py +674 -674
- package/core/persistence_manager.py +712 -712
- package/core/progressive_stats_calculator.py +632 -632
- package/core/regex_pattern_cache.py +529 -529
- package/core/regex_pattern_library.py +350 -350
- package/core/search_operation_manager.py +434 -434
- package/core/settings_defaults_registry.py +1087 -1087
- package/core/settings_integrity_validator.py +1111 -1111
- package/core/settings_serializer.py +557 -557
- package/core/settings_validator.py +1823 -1823
- package/core/smart_stats_calculator.py +709 -709
- package/core/statistics_update_manager.py +619 -619
- package/core/stats_config_manager.py +858 -858
- package/core/streaming_text_handler.py +723 -723
- package/core/task_scheduler.py +596 -596
- package/core/update_pattern_library.py +168 -168
- package/core/visibility_monitor.py +596 -596
- package/core/widget_cache.py +498 -498
- package/mcp.json +51 -61
- package/migrate_data.py +127 -0
- package/package.json +64 -57
- package/pomera.py +7883 -7482
- package/pomera_mcp_server.py +183 -144
- package/requirements.txt +33 -0
- package/scripts/Dockerfile.alpine +43 -0
- package/scripts/Dockerfile.gui-test +54 -0
- package/scripts/Dockerfile.linux +43 -0
- package/scripts/Dockerfile.test-linux +80 -0
- package/scripts/Dockerfile.ubuntu +39 -0
- package/scripts/README.md +53 -0
- package/scripts/build-all.bat +113 -0
- package/scripts/build-docker.bat +53 -0
- package/scripts/build-docker.sh +55 -0
- package/scripts/build-optimized.bat +101 -0
- package/scripts/build.sh +78 -0
- package/scripts/docker-compose.test.yml +27 -0
- package/scripts/docker-compose.yml +32 -0
- package/scripts/postinstall.js +62 -0
- package/scripts/requirements-minimal.txt +33 -0
- package/scripts/test-linux-simple.bat +28 -0
- package/scripts/validate-release-workflow.py +450 -0
- package/tools/__init__.py +4 -4
- package/tools/ai_tools.py +2891 -2891
- package/tools/ascii_art_generator.py +352 -352
- package/tools/base64_tools.py +183 -183
- package/tools/base_tool.py +511 -511
- package/tools/case_tool.py +308 -308
- package/tools/column_tools.py +395 -395
- package/tools/cron_tool.py +884 -884
- package/tools/curl_history.py +600 -600
- package/tools/curl_processor.py +1207 -1207
- package/tools/curl_settings.py +502 -502
- package/tools/curl_tool.py +5467 -5467
- package/tools/diff_viewer.py +1817 -1072
- package/tools/email_extraction_tool.py +248 -248
- package/tools/email_header_analyzer.py +425 -425
- package/tools/extraction_tools.py +250 -250
- package/tools/find_replace.py +2289 -1750
- package/tools/folder_file_reporter.py +1463 -1463
- package/tools/folder_file_reporter_adapter.py +480 -480
- package/tools/generator_tools.py +1216 -1216
- package/tools/hash_generator.py +255 -255
- package/tools/html_tool.py +656 -656
- package/tools/jsonxml_tool.py +729 -729
- package/tools/line_tools.py +419 -419
- package/tools/markdown_tools.py +561 -561
- package/tools/mcp_widget.py +1417 -1417
- package/tools/notes_widget.py +978 -973
- package/tools/number_base_converter.py +372 -372
- package/tools/regex_extractor.py +571 -571
- package/tools/slug_generator.py +310 -310
- package/tools/sorter_tools.py +458 -458
- package/tools/string_escape_tool.py +392 -392
- package/tools/text_statistics_tool.py +365 -365
- package/tools/text_wrapper.py +430 -430
- package/tools/timestamp_converter.py +421 -421
- package/tools/tool_loader.py +710 -710
- package/tools/translator_tools.py +522 -522
- package/tools/url_link_extractor.py +261 -261
- package/tools/url_parser.py +204 -204
- package/tools/whitespace_tools.py +355 -355
- package/tools/word_frequency_counter.py +146 -146
- package/core/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/__pycache__/app_context.cpython-313.pyc +0 -0
- package/core/__pycache__/async_text_processor.cpython-313.pyc +0 -0
- package/core/__pycache__/backup_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/backup_recovery_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/content_hash_cache.cpython-313.pyc +0 -0
- package/core/__pycache__/context_menu.cpython-313.pyc +0 -0
- package/core/__pycache__/data_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/database_connection_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_curl_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_promera_ai_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_schema.cpython-313.pyc +0 -0
- package/core/__pycache__/database_schema_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_settings_manager_interface.cpython-313.pyc +0 -0
- package/core/__pycache__/dialog_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/efficient_line_numbers.cpython-313.pyc +0 -0
- package/core/__pycache__/error_handler.cpython-313.pyc +0 -0
- package/core/__pycache__/error_service.cpython-313.pyc +0 -0
- package/core/__pycache__/event_consolidator.cpython-313.pyc +0 -0
- package/core/__pycache__/memory_efficient_text_widget.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_test_suite.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_find_replace.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_pattern_engine.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_search_highlighter.cpython-313.pyc +0 -0
- package/core/__pycache__/performance_monitor.cpython-313.pyc +0 -0
- package/core/__pycache__/persistence_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/progressive_stats_calculator.cpython-313.pyc +0 -0
- package/core/__pycache__/regex_pattern_cache.cpython-313.pyc +0 -0
- package/core/__pycache__/regex_pattern_library.cpython-313.pyc +0 -0
- package/core/__pycache__/search_operation_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_defaults_registry.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_integrity_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_serializer.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/smart_stats_calculator.cpython-313.pyc +0 -0
- package/core/__pycache__/statistics_update_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/stats_config_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/streaming_text_handler.cpython-313.pyc +0 -0
- package/core/__pycache__/task_scheduler.cpython-313.pyc +0 -0
- package/core/__pycache__/visibility_monitor.cpython-313.pyc +0 -0
- package/core/__pycache__/widget_cache.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/protocol.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/schema.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/server_stdio.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/tool_registry.cpython-313.pyc +0 -0
- package/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- package/tools/__pycache__/ai_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/ascii_art_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/base64_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/base_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/case_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/column_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/cron_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_history.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_processor.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_settings.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/diff_viewer.cpython-313.pyc +0 -0
- package/tools/__pycache__/email_extraction_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/email_header_analyzer.cpython-313.pyc +0 -0
- package/tools/__pycache__/extraction_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/find_replace.cpython-313.pyc +0 -0
- package/tools/__pycache__/folder_file_reporter.cpython-313.pyc +0 -0
- package/tools/__pycache__/folder_file_reporter_adapter.cpython-313.pyc +0 -0
- package/tools/__pycache__/generator_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/hash_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/html_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/huggingface_helper.cpython-313.pyc +0 -0
- package/tools/__pycache__/jsonxml_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/line_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/list_comparator.cpython-313.pyc +0 -0
- package/tools/__pycache__/markdown_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/mcp_widget.cpython-313.pyc +0 -0
- package/tools/__pycache__/notes_widget.cpython-313.pyc +0 -0
- package/tools/__pycache__/number_base_converter.cpython-313.pyc +0 -0
- package/tools/__pycache__/regex_extractor.cpython-313.pyc +0 -0
- package/tools/__pycache__/slug_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/sorter_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/string_escape_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/text_statistics_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/text_wrapper.cpython-313.pyc +0 -0
- package/tools/__pycache__/timestamp_converter.cpython-313.pyc +0 -0
- package/tools/__pycache__/tool_loader.cpython-313.pyc +0 -0
- package/tools/__pycache__/translator_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/url_link_extractor.cpython-313.pyc +0 -0
- package/tools/__pycache__/url_parser.cpython-313.pyc +0 -0
- package/tools/__pycache__/whitespace_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/word_frequency_counter.cpython-313.pyc +0 -0
|
@@ -1,480 +1,480 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Folder File Reporter Adapter for Pomera Integration
|
|
3
|
-
|
|
4
|
-
This adapter integrates the Folder File Reporter into Pomera's dropdown tool system,
|
|
5
|
-
allowing it to work with the main application's 7-tab Input/Output system instead of
|
|
6
|
-
having its own separate tabs.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import tkinter as tk
|
|
10
|
-
from tkinter import ttk, filedialog
|
|
11
|
-
import os
|
|
12
|
-
from tools.folder_file_reporter import FolderFileReporter
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class FolderFileReporterAdapter:
|
|
16
|
-
"""
|
|
17
|
-
Adapter that integrates FolderFileReporter into Pomera's tool system.
|
|
18
|
-
|
|
19
|
-
This adapter creates a simplified UI in the tool settings panel and generates
|
|
20
|
-
reports into the main application's active Input/Output tabs.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
def __init__(self, parent_app):
|
|
24
|
-
"""
|
|
25
|
-
Initialize the adapter.
|
|
26
|
-
|
|
27
|
-
Args:
|
|
28
|
-
parent_app: Reference to the main Pomera application
|
|
29
|
-
"""
|
|
30
|
-
self.app = parent_app
|
|
31
|
-
self.reporter = None
|
|
32
|
-
|
|
33
|
-
# UI variables
|
|
34
|
-
self.input_folder_var = tk.StringVar()
|
|
35
|
-
self.output_folder_var = tk.StringVar()
|
|
36
|
-
|
|
37
|
-
# Add trace callbacks to save settings when folders change
|
|
38
|
-
self.input_folder_var.trace_add('write', lambda *args: self._on_folder_changed())
|
|
39
|
-
self.output_folder_var.trace_add('write', lambda *args: self._on_folder_changed())
|
|
40
|
-
|
|
41
|
-
# Field selection variables
|
|
42
|
-
self.field_selections = {
|
|
43
|
-
'path': tk.BooleanVar(value=True),
|
|
44
|
-
'name': tk.BooleanVar(value=True),
|
|
45
|
-
'size': tk.BooleanVar(value=True),
|
|
46
|
-
'date_modified': tk.BooleanVar(value=True)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
# Configuration variables
|
|
50
|
-
self.separator = tk.StringVar(value=" | ")
|
|
51
|
-
self.folders_only = tk.BooleanVar(value=False)
|
|
52
|
-
self.recursion_mode = tk.StringVar(value="full")
|
|
53
|
-
self.recursion_depth = tk.IntVar(value=2)
|
|
54
|
-
self.size_format = tk.StringVar(value="human")
|
|
55
|
-
self.date_format = tk.StringVar(value="%Y-%m-%d %H:%M:%S")
|
|
56
|
-
|
|
57
|
-
# Add trace callbacks to save settings when any option changes
|
|
58
|
-
for field_var in self.field_selections.values():
|
|
59
|
-
field_var.trace_add('write', lambda *args: self._on_setting_changed())
|
|
60
|
-
|
|
61
|
-
self.separator.trace_add('write', lambda *args: self._on_setting_changed())
|
|
62
|
-
self.folders_only.trace_add('write', lambda *args: self._on_setting_changed())
|
|
63
|
-
self.recursion_mode.trace_add('write', lambda *args: self._on_setting_changed())
|
|
64
|
-
self.recursion_depth.trace_add('write', lambda *args: self._on_setting_changed())
|
|
65
|
-
self.size_format.trace_add('write', lambda *args: self._on_setting_changed())
|
|
66
|
-
self.date_format.trace_add('write', lambda *args: self._on_setting_changed())
|
|
67
|
-
|
|
68
|
-
def create_ui(self, parent_frame):
|
|
69
|
-
"""
|
|
70
|
-
Create the tool settings UI in the provided frame.
|
|
71
|
-
|
|
72
|
-
Args:
|
|
73
|
-
parent_frame: The tool settings frame to add UI elements to
|
|
74
|
-
"""
|
|
75
|
-
# Main container with scrollbar
|
|
76
|
-
canvas = tk.Canvas(parent_frame)
|
|
77
|
-
scrollbar = ttk.Scrollbar(parent_frame, orient="vertical", command=canvas.yview)
|
|
78
|
-
scrollable_frame = ttk.Frame(canvas)
|
|
79
|
-
|
|
80
|
-
scrollable_frame.bind(
|
|
81
|
-
"<Configure>",
|
|
82
|
-
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
|
|
86
|
-
canvas.configure(yscrollcommand=scrollbar.set)
|
|
87
|
-
|
|
88
|
-
# Pack canvas and scrollbar
|
|
89
|
-
canvas.pack(side="left", fill="both", expand=True)
|
|
90
|
-
scrollbar.pack(side="right", fill="y")
|
|
91
|
-
|
|
92
|
-
# Info message (replacing title)
|
|
93
|
-
info_text = ("Select folders and configure options, then click 'Generate Reports'.\n"
|
|
94
|
-
"Reports will appear in the currently active Input and Output tabs.")
|
|
95
|
-
info_label = ttk.Label(scrollable_frame, text=info_text, font=('Arial', 9),
|
|
96
|
-
foreground='gray', justify='center')
|
|
97
|
-
info_label.pack(pady=(10, 10))
|
|
98
|
-
|
|
99
|
-
# Three-column layout
|
|
100
|
-
columns_frame = ttk.Frame(scrollable_frame)
|
|
101
|
-
columns_frame.pack(fill='both', expand=True, padx=10)
|
|
102
|
-
|
|
103
|
-
left_column = ttk.Frame(columns_frame)
|
|
104
|
-
left_column.grid(row=0, column=0, sticky='nsew', padx=(0, 10))
|
|
105
|
-
|
|
106
|
-
middle_column = ttk.Frame(columns_frame)
|
|
107
|
-
middle_column.grid(row=0, column=1, sticky='nsew', padx=(5, 5))
|
|
108
|
-
|
|
109
|
-
right_column = ttk.Frame(columns_frame)
|
|
110
|
-
right_column.grid(row=0, column=2, sticky='nsew', padx=(10, 0))
|
|
111
|
-
|
|
112
|
-
columns_frame.grid_columnconfigure(0, weight=1)
|
|
113
|
-
columns_frame.grid_columnconfigure(1, weight=1)
|
|
114
|
-
columns_frame.grid_columnconfigure(2, weight=1)
|
|
115
|
-
|
|
116
|
-
# LEFT COLUMN
|
|
117
|
-
# Input folder selection - label and field on same line
|
|
118
|
-
input_frame = ttk.Frame(left_column)
|
|
119
|
-
input_frame.grid(row=0, column=0, sticky='ew', pady=(0, 5))
|
|
120
|
-
|
|
121
|
-
ttk.Label(input_frame, text="Input Folder:", font=('TkDefaultFont', 9, 'bold')).pack(side='left', padx=(0, 5))
|
|
122
|
-
ttk.Entry(input_frame, textvariable=self.input_folder_var, width=30).pack(side='left', fill='x', expand=True, padx=(0, 5))
|
|
123
|
-
ttk.Button(input_frame, text="Browse...", command=self._browse_input_folder).pack(side='left')
|
|
124
|
-
|
|
125
|
-
left_column.grid_columnconfigure(0, weight=1)
|
|
126
|
-
|
|
127
|
-
# Folders Only checkbox - above Information Fields
|
|
128
|
-
ttk.Checkbutton(left_column, text="Folders Only", variable=self.folders_only).grid(row=1, column=0, sticky='w', pady=(15, 10))
|
|
129
|
-
|
|
130
|
-
# Information Fields
|
|
131
|
-
fields_label = ttk.Label(left_column, text="Information Fields:", font=('TkDefaultFont', 9, 'bold'))
|
|
132
|
-
fields_label.grid(row=2, column=0, sticky='w', pady=(5, 5))
|
|
133
|
-
|
|
134
|
-
fields_frame = ttk.Frame(left_column)
|
|
135
|
-
fields_frame.grid(row=3, column=0, sticky='w', pady=(0, 15))
|
|
136
|
-
|
|
137
|
-
ttk.Checkbutton(fields_frame, text="Path", variable=self.field_selections['path']).grid(row=0, column=0, sticky='w', pady=2)
|
|
138
|
-
ttk.Checkbutton(fields_frame, text="File Name", variable=self.field_selections['name']).grid(row=1, column=0, sticky='w', pady=2)
|
|
139
|
-
ttk.Checkbutton(fields_frame, text="Size", variable=self.field_selections['size']).grid(row=2, column=0, sticky='w', pady=2)
|
|
140
|
-
ttk.Checkbutton(fields_frame, text="Date Modified", variable=self.field_selections['date_modified']).grid(row=3, column=0, sticky='w', pady=2)
|
|
141
|
-
|
|
142
|
-
# MIDDLE COLUMN
|
|
143
|
-
# Output folder selection - label and field on same line
|
|
144
|
-
output_frame = ttk.Frame(middle_column)
|
|
145
|
-
output_frame.grid(row=0, column=0, sticky='ew', pady=(0, 5))
|
|
146
|
-
|
|
147
|
-
ttk.Label(output_frame, text="Output Folder:", font=('TkDefaultFont', 9, 'bold')).pack(side='left', padx=(0, 5))
|
|
148
|
-
ttk.Entry(output_frame, textvariable=self.output_folder_var, width=30).pack(side='left', fill='x', expand=True, padx=(0, 5))
|
|
149
|
-
ttk.Button(output_frame, text="Browse...", command=self._browse_output_folder).pack(side='left')
|
|
150
|
-
|
|
151
|
-
middle_column.grid_columnconfigure(0, weight=1)
|
|
152
|
-
|
|
153
|
-
# Recursion
|
|
154
|
-
recursion_label = ttk.Label(middle_column, text="Recursion:", font=('TkDefaultFont', 9, 'bold'))
|
|
155
|
-
recursion_label.grid(row=1, column=0, sticky='w', pady=(15, 5))
|
|
156
|
-
|
|
157
|
-
recursion_frame = ttk.Frame(middle_column)
|
|
158
|
-
recursion_frame.grid(row=2, column=0, sticky='w', pady=(0, 15))
|
|
159
|
-
|
|
160
|
-
ttk.Radiobutton(recursion_frame, text="None", variable=self.recursion_mode, value="none", command=self._update_depth_visibility).grid(row=0, column=0, sticky='w', pady=2)
|
|
161
|
-
|
|
162
|
-
limited_frame = ttk.Frame(recursion_frame)
|
|
163
|
-
limited_frame.grid(row=1, column=0, sticky='w', pady=2)
|
|
164
|
-
ttk.Radiobutton(limited_frame, text="Limited", variable=self.recursion_mode, value="limited", command=self._update_depth_visibility).pack(side='left')
|
|
165
|
-
|
|
166
|
-
self.depth_frame = ttk.Frame(limited_frame)
|
|
167
|
-
self.depth_frame.pack(side='left', padx=(5, 0))
|
|
168
|
-
ttk.Label(self.depth_frame, text="Depth:").pack(side='left', padx=(0, 5))
|
|
169
|
-
ttk.Spinbox(self.depth_frame, from_=1, to=20, width=5, textvariable=self.recursion_depth).pack(side='left')
|
|
170
|
-
|
|
171
|
-
ttk.Radiobutton(recursion_frame, text="Full", variable=self.recursion_mode, value="full", command=self._update_depth_visibility).grid(row=2, column=0, sticky='w', pady=2)
|
|
172
|
-
|
|
173
|
-
# Generate Reports button under Recursion section
|
|
174
|
-
process_btn = ttk.Button(middle_column, text="Generate Reports", command=self._generate_reports)
|
|
175
|
-
process_btn.grid(row=3, column=0, sticky='w', pady=(10, 0))
|
|
176
|
-
|
|
177
|
-
# RIGHT COLUMN
|
|
178
|
-
# Separator - label and field on same line
|
|
179
|
-
separator_frame = ttk.Frame(right_column)
|
|
180
|
-
separator_frame.grid(row=0, column=0, sticky='ew', pady=(0, 5))
|
|
181
|
-
|
|
182
|
-
ttk.Label(separator_frame, text="Separator:", font=('TkDefaultFont', 9, 'bold')).pack(side='left', padx=(0, 5))
|
|
183
|
-
ttk.Entry(separator_frame, textvariable=self.separator, width=15).pack(side='left')
|
|
184
|
-
|
|
185
|
-
# Separator tip below
|
|
186
|
-
ttk.Label(right_column, text="(Use \\t for tab, \\n for newline)", font=('TkDefaultFont', 8), foreground='gray').grid(row=1, column=0, sticky='w', pady=(0, 10))
|
|
187
|
-
|
|
188
|
-
right_column.grid_columnconfigure(0, weight=1)
|
|
189
|
-
|
|
190
|
-
# Date Format - label and field on same line
|
|
191
|
-
date_frame = ttk.Frame(right_column)
|
|
192
|
-
date_frame.grid(row=2, column=0, sticky='ew', pady=(5, 5))
|
|
193
|
-
|
|
194
|
-
ttk.Label(date_frame, text="Date Format:", font=('TkDefaultFont', 9, 'bold')).pack(side='left', padx=(0, 5))
|
|
195
|
-
ttk.Entry(date_frame, textvariable=self.date_format, width=20).pack(side='left')
|
|
196
|
-
|
|
197
|
-
# Date format tip below
|
|
198
|
-
ttk.Label(right_column, text="(e.g., %Y-%m-%d %H:%M:%S)", font=('TkDefaultFont', 8), foreground='gray').grid(row=3, column=0, sticky='w', pady=(0, 10))
|
|
199
|
-
|
|
200
|
-
# Size Format
|
|
201
|
-
size_label = ttk.Label(right_column, text="Size Format:", font=('TkDefaultFont', 9, 'bold'))
|
|
202
|
-
size_label.grid(row=4, column=0, sticky='w', pady=(5, 5))
|
|
203
|
-
|
|
204
|
-
size_frame = ttk.Frame(right_column)
|
|
205
|
-
size_frame.grid(row=5, column=0, sticky='w', pady=(0, 5))
|
|
206
|
-
|
|
207
|
-
ttk.Radiobutton(size_frame, text="Bytes", variable=self.size_format, value="bytes").grid(row=0, column=0, sticky='w', pady=2)
|
|
208
|
-
ttk.Radiobutton(size_frame, text="Human Readable (KB, MB, GB)", variable=self.size_format, value="human").grid(row=1, column=0, sticky='w', pady=2)
|
|
209
|
-
|
|
210
|
-
# Update depth visibility based on initial mode
|
|
211
|
-
self._update_depth_visibility()
|
|
212
|
-
|
|
213
|
-
return parent_frame
|
|
214
|
-
|
|
215
|
-
def _update_depth_visibility(self):
|
|
216
|
-
"""Show/hide depth spinbox based on recursion mode."""
|
|
217
|
-
if hasattr(self, 'depth_frame'):
|
|
218
|
-
if self.recursion_mode.get() == "limited":
|
|
219
|
-
self.depth_frame.pack(side='left', padx=(5, 0))
|
|
220
|
-
else:
|
|
221
|
-
self.depth_frame.pack_forget()
|
|
222
|
-
|
|
223
|
-
def _browse_input_folder(self):
|
|
224
|
-
"""Open folder browser for Input folder selection."""
|
|
225
|
-
folder = filedialog.askdirectory(title="Select Input Folder", parent=self.app)
|
|
226
|
-
if folder:
|
|
227
|
-
self.input_folder_var.set(folder)
|
|
228
|
-
self._save_all_settings()
|
|
229
|
-
|
|
230
|
-
def _browse_output_folder(self):
|
|
231
|
-
"""Open folder browser for Output folder selection."""
|
|
232
|
-
folder = filedialog.askdirectory(title="Select Output Folder", parent=self.app)
|
|
233
|
-
if folder:
|
|
234
|
-
self.output_folder_var.set(folder)
|
|
235
|
-
self._save_all_settings()
|
|
236
|
-
|
|
237
|
-
def _on_folder_changed(self):
|
|
238
|
-
"""Callback when folder paths change (typed or browsed)."""
|
|
239
|
-
# Debounce the save to avoid excessive writes when typing
|
|
240
|
-
if hasattr(self, '_save_timer'):
|
|
241
|
-
self.app.after_cancel(self._save_timer)
|
|
242
|
-
self._save_timer = self.app.after(1000, self._save_all_settings) # Save after 1 second of no changes
|
|
243
|
-
|
|
244
|
-
def _on_setting_changed(self):
|
|
245
|
-
"""Callback when any setting changes (checkboxes, radio buttons, etc)."""
|
|
246
|
-
# Debounce the save to avoid excessive writes
|
|
247
|
-
if hasattr(self, '_setting_save_timer'):
|
|
248
|
-
self.app.after_cancel(self._setting_save_timer)
|
|
249
|
-
self._setting_save_timer = self.app.after(500, self._save_all_settings) # Save after 0.5 seconds
|
|
250
|
-
|
|
251
|
-
def _save_all_settings(self):
|
|
252
|
-
"""Save all settings (folders, fields, options) when they change."""
|
|
253
|
-
if hasattr(self.app, 'settings') and hasattr(self.app, 'save_settings'):
|
|
254
|
-
# Update the settings
|
|
255
|
-
if "tool_settings" in self.app.settings:
|
|
256
|
-
if "Folder File Reporter" not in self.app.settings["tool_settings"]:
|
|
257
|
-
self.app.settings["tool_settings"]["Folder File Reporter"] = {}
|
|
258
|
-
|
|
259
|
-
# Save folder paths
|
|
260
|
-
self.app.settings["tool_settings"]["Folder File Reporter"]["last_input_folder"] = self.input_folder_var.get()
|
|
261
|
-
self.app.settings["tool_settings"]["Folder File Reporter"]["last_output_folder"] = self.output_folder_var.get()
|
|
262
|
-
|
|
263
|
-
# Save field selections
|
|
264
|
-
self.app.settings["tool_settings"]["Folder File Reporter"]["field_selections"] = {
|
|
265
|
-
field: var.get() for field, var in self.field_selections.items()
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
# Save other options
|
|
269
|
-
self.app.settings["tool_settings"]["Folder File Reporter"]["separator"] = self.separator.get()
|
|
270
|
-
self.app.settings["tool_settings"]["Folder File Reporter"]["folders_only"] = self.folders_only.get()
|
|
271
|
-
self.app.settings["tool_settings"]["Folder File Reporter"]["recursion_mode"] = self.recursion_mode.get()
|
|
272
|
-
self.app.settings["tool_settings"]["Folder File Reporter"]["recursion_depth"] = self.recursion_depth.get()
|
|
273
|
-
self.app.settings["tool_settings"]["Folder File Reporter"]["size_format"] = self.size_format.get()
|
|
274
|
-
self.app.settings["tool_settings"]["Folder File Reporter"]["date_format"] = self.date_format.get()
|
|
275
|
-
|
|
276
|
-
# Save to file
|
|
277
|
-
self.app.save_settings()
|
|
278
|
-
|
|
279
|
-
def _generate_reports(self):
|
|
280
|
-
"""
|
|
281
|
-
Generate reports and write them to the active Input/Output tabs.
|
|
282
|
-
"""
|
|
283
|
-
input_folder = self.input_folder_var.get().strip()
|
|
284
|
-
output_folder = self.output_folder_var.get().strip()
|
|
285
|
-
|
|
286
|
-
if not input_folder and not output_folder:
|
|
287
|
-
if self.app.dialog_manager:
|
|
288
|
-
self.app.dialog_manager.show_warning(
|
|
289
|
-
"No Folders Selected",
|
|
290
|
-
"Please select at least one folder to generate a report."
|
|
291
|
-
)
|
|
292
|
-
else:
|
|
293
|
-
tk.messagebox.showwarning(
|
|
294
|
-
"No Folders Selected",
|
|
295
|
-
"Please select at least one folder to generate a report.",
|
|
296
|
-
parent=self.app
|
|
297
|
-
)
|
|
298
|
-
return
|
|
299
|
-
|
|
300
|
-
# Get active Input and Output text widgets
|
|
301
|
-
input_tab_index = self.app.input_notebook.index(self.app.input_notebook.select())
|
|
302
|
-
output_tab_index = self.app.output_notebook.index(self.app.output_notebook.select())
|
|
303
|
-
|
|
304
|
-
active_input_tab = self.app.input_tabs[input_tab_index]
|
|
305
|
-
active_output_tab = self.app.output_tabs[output_tab_index]
|
|
306
|
-
|
|
307
|
-
# Debug logging
|
|
308
|
-
if hasattr(self.app, 'logger') and self.app.logger:
|
|
309
|
-
self.app.logger.info(f"Active Input tab index: {input_tab_index}")
|
|
310
|
-
self.app.logger.info(f"Active Output tab index: {output_tab_index}")
|
|
311
|
-
self.app.logger.info(f"Input text widget: {active_input_tab.text}")
|
|
312
|
-
self.app.logger.info(f"Output text widget: {active_output_tab.text}")
|
|
313
|
-
|
|
314
|
-
try:
|
|
315
|
-
# Create reporter WITHOUT calling _create_ui (which would create its own text widgets)
|
|
316
|
-
# We'll manually set up the reporter to use the main app's text widgets
|
|
317
|
-
reporter = FolderFileReporter.__new__(FolderFileReporter)
|
|
318
|
-
|
|
319
|
-
# Manually initialize the reporter without calling __init__ (which calls _create_ui)
|
|
320
|
-
reporter.parent = None # We don't need a parent since we're not creating UI
|
|
321
|
-
reporter.dialog_manager = self.app.dialog_manager
|
|
322
|
-
reporter.input_text_widget = active_input_tab.text
|
|
323
|
-
reporter.output_text_widget = active_output_tab.text
|
|
324
|
-
reporter.settings_file = "settings.json"
|
|
325
|
-
reporter.tool_key = "Folder File Reporter"
|
|
326
|
-
|
|
327
|
-
# Initialize UI variables
|
|
328
|
-
reporter.input_folder_path = tk.StringVar()
|
|
329
|
-
reporter.output_folder_path = tk.StringVar()
|
|
330
|
-
|
|
331
|
-
# Field selection variables
|
|
332
|
-
reporter.field_selections = {
|
|
333
|
-
'path': tk.BooleanVar(value=True),
|
|
334
|
-
'name': tk.BooleanVar(value=True),
|
|
335
|
-
'size': tk.BooleanVar(value=True),
|
|
336
|
-
'date_modified': tk.BooleanVar(value=True)
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
# Configuration variables
|
|
340
|
-
reporter.separator = tk.StringVar(value=" | ")
|
|
341
|
-
reporter.folders_only = tk.BooleanVar(value=False)
|
|
342
|
-
reporter.recursion_mode = tk.StringVar(value="full")
|
|
343
|
-
reporter.recursion_depth = tk.IntVar(value=2)
|
|
344
|
-
reporter.size_format = tk.StringVar(value="human")
|
|
345
|
-
reporter.date_format = tk.StringVar(value="%Y-%m-%d %H:%M:%S")
|
|
346
|
-
|
|
347
|
-
# Use the main app's text widgets directly
|
|
348
|
-
reporter.input_text = active_input_tab.text
|
|
349
|
-
reporter.output_text = active_output_tab.text
|
|
350
|
-
|
|
351
|
-
# Debug: Verify text widgets are set correctly
|
|
352
|
-
if hasattr(self.app, 'logger') and self.app.logger:
|
|
353
|
-
self.app.logger.info(f"Reporter input_text set to: {reporter.input_text}")
|
|
354
|
-
self.app.logger.info(f"Reporter output_text set to: {reporter.output_text}")
|
|
355
|
-
|
|
356
|
-
# CRITICAL: Enable output tab for writing (Pomera keeps output tabs disabled/read-only)
|
|
357
|
-
active_output_tab.text.config(state="normal")
|
|
358
|
-
|
|
359
|
-
# Set the folder paths
|
|
360
|
-
reporter.input_folder_path.set(input_folder)
|
|
361
|
-
reporter.output_folder_path.set(output_folder)
|
|
362
|
-
|
|
363
|
-
# Debug: Log folder paths
|
|
364
|
-
if hasattr(self.app, 'logger') and self.app.logger:
|
|
365
|
-
self.app.logger.info(f"Input folder path: {input_folder}")
|
|
366
|
-
self.app.logger.info(f"Output folder path: {output_folder}")
|
|
367
|
-
|
|
368
|
-
# Transfer all settings from adapter to reporter
|
|
369
|
-
for field, var in self.field_selections.items():
|
|
370
|
-
reporter.field_selections[field].set(var.get())
|
|
371
|
-
|
|
372
|
-
reporter.separator.set(self.separator.get())
|
|
373
|
-
reporter.folders_only.set(self.folders_only.get())
|
|
374
|
-
reporter.recursion_mode.set(self.recursion_mode.get())
|
|
375
|
-
reporter.recursion_depth.set(self.recursion_depth.get())
|
|
376
|
-
reporter.size_format.set(self.size_format.get())
|
|
377
|
-
reporter.date_format.set(self.date_format.get())
|
|
378
|
-
|
|
379
|
-
# Generate the reports
|
|
380
|
-
reporter.generate_report()
|
|
381
|
-
|
|
382
|
-
# Re-disable output tab to maintain Pomera's read-only convention
|
|
383
|
-
active_output_tab.text.config(state="disabled")
|
|
384
|
-
|
|
385
|
-
# Verify content was written
|
|
386
|
-
if hasattr(self.app, 'logger') and self.app.logger:
|
|
387
|
-
input_content = active_input_tab.text.get("1.0", "end-1c")
|
|
388
|
-
output_content = active_output_tab.text.get("1.0", "end-1c")
|
|
389
|
-
self.app.logger.info(f"Generated folder reports - Input: {input_folder}, Output: {output_folder}")
|
|
390
|
-
self.app.logger.info(f"Input tab content length: {len(input_content)} chars")
|
|
391
|
-
self.app.logger.info(f"Output tab content length: {len(output_content)} chars")
|
|
392
|
-
if input_content:
|
|
393
|
-
self.app.logger.info(f"Input tab first 100 chars: {input_content[:100]}")
|
|
394
|
-
if output_content:
|
|
395
|
-
self.app.logger.info(f"Output tab first 100 chars: {output_content[:100]}")
|
|
396
|
-
|
|
397
|
-
except Exception as e:
|
|
398
|
-
error_msg = f"Error generating reports: {e}"
|
|
399
|
-
self.app.logger.error(error_msg, exc_info=True)
|
|
400
|
-
if self.app.dialog_manager:
|
|
401
|
-
self.app.dialog_manager.show_error("Report Generation Error", error_msg)
|
|
402
|
-
else:
|
|
403
|
-
tk.messagebox.showerror("Report Generation Error", error_msg, parent=self.app)
|
|
404
|
-
|
|
405
|
-
def get_default_settings(self):
|
|
406
|
-
"""
|
|
407
|
-
Get default settings for the tool.
|
|
408
|
-
|
|
409
|
-
Returns:
|
|
410
|
-
dict: Default settings
|
|
411
|
-
"""
|
|
412
|
-
return {
|
|
413
|
-
'last_input_folder': '',
|
|
414
|
-
'last_output_folder': '',
|
|
415
|
-
'field_selections': {
|
|
416
|
-
'path': True,
|
|
417
|
-
'name': True,
|
|
418
|
-
'size': True,
|
|
419
|
-
'date_modified': True
|
|
420
|
-
},
|
|
421
|
-
'separator': ' | ',
|
|
422
|
-
'folders_only': False,
|
|
423
|
-
'recursion_mode': 'full',
|
|
424
|
-
'recursion_depth': 2,
|
|
425
|
-
'size_format': 'human',
|
|
426
|
-
'date_format': '%Y-%m-%d %H:%M:%S'
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
def load_settings(self, settings):
|
|
430
|
-
"""
|
|
431
|
-
Load settings from the application settings.
|
|
432
|
-
|
|
433
|
-
Args:
|
|
434
|
-
settings: Dictionary of settings to load
|
|
435
|
-
"""
|
|
436
|
-
if 'last_input_folder' in settings:
|
|
437
|
-
self.input_folder_var.set(settings['last_input_folder'])
|
|
438
|
-
if 'last_output_folder' in settings:
|
|
439
|
-
self.output_folder_var.set(settings['last_output_folder'])
|
|
440
|
-
|
|
441
|
-
# Load field selections
|
|
442
|
-
if 'field_selections' in settings:
|
|
443
|
-
for field, value in settings['field_selections'].items():
|
|
444
|
-
if field in self.field_selections:
|
|
445
|
-
self.field_selections[field].set(value)
|
|
446
|
-
|
|
447
|
-
# Load other settings
|
|
448
|
-
if 'separator' in settings:
|
|
449
|
-
self.separator.set(settings['separator'])
|
|
450
|
-
if 'folders_only' in settings:
|
|
451
|
-
self.folders_only.set(settings['folders_only'])
|
|
452
|
-
if 'recursion_mode' in settings:
|
|
453
|
-
self.recursion_mode.set(settings['recursion_mode'])
|
|
454
|
-
if 'recursion_depth' in settings:
|
|
455
|
-
self.recursion_depth.set(settings['recursion_depth'])
|
|
456
|
-
if 'size_format' in settings:
|
|
457
|
-
self.size_format.set(settings['size_format'])
|
|
458
|
-
if 'date_format' in settings:
|
|
459
|
-
self.date_format.set(settings['date_format'])
|
|
460
|
-
|
|
461
|
-
def save_settings(self):
|
|
462
|
-
"""
|
|
463
|
-
Save current settings.
|
|
464
|
-
|
|
465
|
-
Returns:
|
|
466
|
-
dict: Current settings to save
|
|
467
|
-
"""
|
|
468
|
-
return {
|
|
469
|
-
'last_input_folder': self.input_folder_var.get(),
|
|
470
|
-
'last_output_folder': self.output_folder_var.get(),
|
|
471
|
-
'field_selections': {
|
|
472
|
-
field: var.get() for field, var in self.field_selections.items()
|
|
473
|
-
},
|
|
474
|
-
'separator': self.separator.get(),
|
|
475
|
-
'folders_only': self.folders_only.get(),
|
|
476
|
-
'recursion_mode': self.recursion_mode.get(),
|
|
477
|
-
'recursion_depth': self.recursion_depth.get(),
|
|
478
|
-
'size_format': self.size_format.get(),
|
|
479
|
-
'date_format': self.date_format.get()
|
|
480
|
-
}
|
|
1
|
+
"""
|
|
2
|
+
Folder File Reporter Adapter for Pomera Integration
|
|
3
|
+
|
|
4
|
+
This adapter integrates the Folder File Reporter into Pomera's dropdown tool system,
|
|
5
|
+
allowing it to work with the main application's 7-tab Input/Output system instead of
|
|
6
|
+
having its own separate tabs.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import tkinter as tk
|
|
10
|
+
from tkinter import ttk, filedialog
|
|
11
|
+
import os
|
|
12
|
+
from tools.folder_file_reporter import FolderFileReporter
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FolderFileReporterAdapter:
|
|
16
|
+
"""
|
|
17
|
+
Adapter that integrates FolderFileReporter into Pomera's tool system.
|
|
18
|
+
|
|
19
|
+
This adapter creates a simplified UI in the tool settings panel and generates
|
|
20
|
+
reports into the main application's active Input/Output tabs.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, parent_app):
|
|
24
|
+
"""
|
|
25
|
+
Initialize the adapter.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
parent_app: Reference to the main Pomera application
|
|
29
|
+
"""
|
|
30
|
+
self.app = parent_app
|
|
31
|
+
self.reporter = None
|
|
32
|
+
|
|
33
|
+
# UI variables
|
|
34
|
+
self.input_folder_var = tk.StringVar()
|
|
35
|
+
self.output_folder_var = tk.StringVar()
|
|
36
|
+
|
|
37
|
+
# Add trace callbacks to save settings when folders change
|
|
38
|
+
self.input_folder_var.trace_add('write', lambda *args: self._on_folder_changed())
|
|
39
|
+
self.output_folder_var.trace_add('write', lambda *args: self._on_folder_changed())
|
|
40
|
+
|
|
41
|
+
# Field selection variables
|
|
42
|
+
self.field_selections = {
|
|
43
|
+
'path': tk.BooleanVar(value=True),
|
|
44
|
+
'name': tk.BooleanVar(value=True),
|
|
45
|
+
'size': tk.BooleanVar(value=True),
|
|
46
|
+
'date_modified': tk.BooleanVar(value=True)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Configuration variables
|
|
50
|
+
self.separator = tk.StringVar(value=" | ")
|
|
51
|
+
self.folders_only = tk.BooleanVar(value=False)
|
|
52
|
+
self.recursion_mode = tk.StringVar(value="full")
|
|
53
|
+
self.recursion_depth = tk.IntVar(value=2)
|
|
54
|
+
self.size_format = tk.StringVar(value="human")
|
|
55
|
+
self.date_format = tk.StringVar(value="%Y-%m-%d %H:%M:%S")
|
|
56
|
+
|
|
57
|
+
# Add trace callbacks to save settings when any option changes
|
|
58
|
+
for field_var in self.field_selections.values():
|
|
59
|
+
field_var.trace_add('write', lambda *args: self._on_setting_changed())
|
|
60
|
+
|
|
61
|
+
self.separator.trace_add('write', lambda *args: self._on_setting_changed())
|
|
62
|
+
self.folders_only.trace_add('write', lambda *args: self._on_setting_changed())
|
|
63
|
+
self.recursion_mode.trace_add('write', lambda *args: self._on_setting_changed())
|
|
64
|
+
self.recursion_depth.trace_add('write', lambda *args: self._on_setting_changed())
|
|
65
|
+
self.size_format.trace_add('write', lambda *args: self._on_setting_changed())
|
|
66
|
+
self.date_format.trace_add('write', lambda *args: self._on_setting_changed())
|
|
67
|
+
|
|
68
|
+
def create_ui(self, parent_frame):
|
|
69
|
+
"""
|
|
70
|
+
Create the tool settings UI in the provided frame.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
parent_frame: The tool settings frame to add UI elements to
|
|
74
|
+
"""
|
|
75
|
+
# Main container with scrollbar
|
|
76
|
+
canvas = tk.Canvas(parent_frame)
|
|
77
|
+
scrollbar = ttk.Scrollbar(parent_frame, orient="vertical", command=canvas.yview)
|
|
78
|
+
scrollable_frame = ttk.Frame(canvas)
|
|
79
|
+
|
|
80
|
+
scrollable_frame.bind(
|
|
81
|
+
"<Configure>",
|
|
82
|
+
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
|
|
86
|
+
canvas.configure(yscrollcommand=scrollbar.set)
|
|
87
|
+
|
|
88
|
+
# Pack canvas and scrollbar
|
|
89
|
+
canvas.pack(side="left", fill="both", expand=True)
|
|
90
|
+
scrollbar.pack(side="right", fill="y")
|
|
91
|
+
|
|
92
|
+
# Info message (replacing title)
|
|
93
|
+
info_text = ("Select folders and configure options, then click 'Generate Reports'.\n"
|
|
94
|
+
"Reports will appear in the currently active Input and Output tabs.")
|
|
95
|
+
info_label = ttk.Label(scrollable_frame, text=info_text, font=('Arial', 9),
|
|
96
|
+
foreground='gray', justify='center')
|
|
97
|
+
info_label.pack(pady=(10, 10))
|
|
98
|
+
|
|
99
|
+
# Three-column layout
|
|
100
|
+
columns_frame = ttk.Frame(scrollable_frame)
|
|
101
|
+
columns_frame.pack(fill='both', expand=True, padx=10)
|
|
102
|
+
|
|
103
|
+
left_column = ttk.Frame(columns_frame)
|
|
104
|
+
left_column.grid(row=0, column=0, sticky='nsew', padx=(0, 10))
|
|
105
|
+
|
|
106
|
+
middle_column = ttk.Frame(columns_frame)
|
|
107
|
+
middle_column.grid(row=0, column=1, sticky='nsew', padx=(5, 5))
|
|
108
|
+
|
|
109
|
+
right_column = ttk.Frame(columns_frame)
|
|
110
|
+
right_column.grid(row=0, column=2, sticky='nsew', padx=(10, 0))
|
|
111
|
+
|
|
112
|
+
columns_frame.grid_columnconfigure(0, weight=1)
|
|
113
|
+
columns_frame.grid_columnconfigure(1, weight=1)
|
|
114
|
+
columns_frame.grid_columnconfigure(2, weight=1)
|
|
115
|
+
|
|
116
|
+
# LEFT COLUMN
|
|
117
|
+
# Input folder selection - label and field on same line
|
|
118
|
+
input_frame = ttk.Frame(left_column)
|
|
119
|
+
input_frame.grid(row=0, column=0, sticky='ew', pady=(0, 5))
|
|
120
|
+
|
|
121
|
+
ttk.Label(input_frame, text="Input Folder:", font=('TkDefaultFont', 9, 'bold')).pack(side='left', padx=(0, 5))
|
|
122
|
+
ttk.Entry(input_frame, textvariable=self.input_folder_var, width=30).pack(side='left', fill='x', expand=True, padx=(0, 5))
|
|
123
|
+
ttk.Button(input_frame, text="Browse...", command=self._browse_input_folder).pack(side='left')
|
|
124
|
+
|
|
125
|
+
left_column.grid_columnconfigure(0, weight=1)
|
|
126
|
+
|
|
127
|
+
# Folders Only checkbox - above Information Fields
|
|
128
|
+
ttk.Checkbutton(left_column, text="Folders Only", variable=self.folders_only).grid(row=1, column=0, sticky='w', pady=(15, 10))
|
|
129
|
+
|
|
130
|
+
# Information Fields
|
|
131
|
+
fields_label = ttk.Label(left_column, text="Information Fields:", font=('TkDefaultFont', 9, 'bold'))
|
|
132
|
+
fields_label.grid(row=2, column=0, sticky='w', pady=(5, 5))
|
|
133
|
+
|
|
134
|
+
fields_frame = ttk.Frame(left_column)
|
|
135
|
+
fields_frame.grid(row=3, column=0, sticky='w', pady=(0, 15))
|
|
136
|
+
|
|
137
|
+
ttk.Checkbutton(fields_frame, text="Path", variable=self.field_selections['path']).grid(row=0, column=0, sticky='w', pady=2)
|
|
138
|
+
ttk.Checkbutton(fields_frame, text="File Name", variable=self.field_selections['name']).grid(row=1, column=0, sticky='w', pady=2)
|
|
139
|
+
ttk.Checkbutton(fields_frame, text="Size", variable=self.field_selections['size']).grid(row=2, column=0, sticky='w', pady=2)
|
|
140
|
+
ttk.Checkbutton(fields_frame, text="Date Modified", variable=self.field_selections['date_modified']).grid(row=3, column=0, sticky='w', pady=2)
|
|
141
|
+
|
|
142
|
+
# MIDDLE COLUMN
|
|
143
|
+
# Output folder selection - label and field on same line
|
|
144
|
+
output_frame = ttk.Frame(middle_column)
|
|
145
|
+
output_frame.grid(row=0, column=0, sticky='ew', pady=(0, 5))
|
|
146
|
+
|
|
147
|
+
ttk.Label(output_frame, text="Output Folder:", font=('TkDefaultFont', 9, 'bold')).pack(side='left', padx=(0, 5))
|
|
148
|
+
ttk.Entry(output_frame, textvariable=self.output_folder_var, width=30).pack(side='left', fill='x', expand=True, padx=(0, 5))
|
|
149
|
+
ttk.Button(output_frame, text="Browse...", command=self._browse_output_folder).pack(side='left')
|
|
150
|
+
|
|
151
|
+
middle_column.grid_columnconfigure(0, weight=1)
|
|
152
|
+
|
|
153
|
+
# Recursion
|
|
154
|
+
recursion_label = ttk.Label(middle_column, text="Recursion:", font=('TkDefaultFont', 9, 'bold'))
|
|
155
|
+
recursion_label.grid(row=1, column=0, sticky='w', pady=(15, 5))
|
|
156
|
+
|
|
157
|
+
recursion_frame = ttk.Frame(middle_column)
|
|
158
|
+
recursion_frame.grid(row=2, column=0, sticky='w', pady=(0, 15))
|
|
159
|
+
|
|
160
|
+
ttk.Radiobutton(recursion_frame, text="None", variable=self.recursion_mode, value="none", command=self._update_depth_visibility).grid(row=0, column=0, sticky='w', pady=2)
|
|
161
|
+
|
|
162
|
+
limited_frame = ttk.Frame(recursion_frame)
|
|
163
|
+
limited_frame.grid(row=1, column=0, sticky='w', pady=2)
|
|
164
|
+
ttk.Radiobutton(limited_frame, text="Limited", variable=self.recursion_mode, value="limited", command=self._update_depth_visibility).pack(side='left')
|
|
165
|
+
|
|
166
|
+
self.depth_frame = ttk.Frame(limited_frame)
|
|
167
|
+
self.depth_frame.pack(side='left', padx=(5, 0))
|
|
168
|
+
ttk.Label(self.depth_frame, text="Depth:").pack(side='left', padx=(0, 5))
|
|
169
|
+
ttk.Spinbox(self.depth_frame, from_=1, to=20, width=5, textvariable=self.recursion_depth).pack(side='left')
|
|
170
|
+
|
|
171
|
+
ttk.Radiobutton(recursion_frame, text="Full", variable=self.recursion_mode, value="full", command=self._update_depth_visibility).grid(row=2, column=0, sticky='w', pady=2)
|
|
172
|
+
|
|
173
|
+
# Generate Reports button under Recursion section
|
|
174
|
+
process_btn = ttk.Button(middle_column, text="Generate Reports", command=self._generate_reports)
|
|
175
|
+
process_btn.grid(row=3, column=0, sticky='w', pady=(10, 0))
|
|
176
|
+
|
|
177
|
+
# RIGHT COLUMN
|
|
178
|
+
# Separator - label and field on same line
|
|
179
|
+
separator_frame = ttk.Frame(right_column)
|
|
180
|
+
separator_frame.grid(row=0, column=0, sticky='ew', pady=(0, 5))
|
|
181
|
+
|
|
182
|
+
ttk.Label(separator_frame, text="Separator:", font=('TkDefaultFont', 9, 'bold')).pack(side='left', padx=(0, 5))
|
|
183
|
+
ttk.Entry(separator_frame, textvariable=self.separator, width=15).pack(side='left')
|
|
184
|
+
|
|
185
|
+
# Separator tip below
|
|
186
|
+
ttk.Label(right_column, text="(Use \\t for tab, \\n for newline)", font=('TkDefaultFont', 8), foreground='gray').grid(row=1, column=0, sticky='w', pady=(0, 10))
|
|
187
|
+
|
|
188
|
+
right_column.grid_columnconfigure(0, weight=1)
|
|
189
|
+
|
|
190
|
+
# Date Format - label and field on same line
|
|
191
|
+
date_frame = ttk.Frame(right_column)
|
|
192
|
+
date_frame.grid(row=2, column=0, sticky='ew', pady=(5, 5))
|
|
193
|
+
|
|
194
|
+
ttk.Label(date_frame, text="Date Format:", font=('TkDefaultFont', 9, 'bold')).pack(side='left', padx=(0, 5))
|
|
195
|
+
ttk.Entry(date_frame, textvariable=self.date_format, width=20).pack(side='left')
|
|
196
|
+
|
|
197
|
+
# Date format tip below
|
|
198
|
+
ttk.Label(right_column, text="(e.g., %Y-%m-%d %H:%M:%S)", font=('TkDefaultFont', 8), foreground='gray').grid(row=3, column=0, sticky='w', pady=(0, 10))
|
|
199
|
+
|
|
200
|
+
# Size Format
|
|
201
|
+
size_label = ttk.Label(right_column, text="Size Format:", font=('TkDefaultFont', 9, 'bold'))
|
|
202
|
+
size_label.grid(row=4, column=0, sticky='w', pady=(5, 5))
|
|
203
|
+
|
|
204
|
+
size_frame = ttk.Frame(right_column)
|
|
205
|
+
size_frame.grid(row=5, column=0, sticky='w', pady=(0, 5))
|
|
206
|
+
|
|
207
|
+
ttk.Radiobutton(size_frame, text="Bytes", variable=self.size_format, value="bytes").grid(row=0, column=0, sticky='w', pady=2)
|
|
208
|
+
ttk.Radiobutton(size_frame, text="Human Readable (KB, MB, GB)", variable=self.size_format, value="human").grid(row=1, column=0, sticky='w', pady=2)
|
|
209
|
+
|
|
210
|
+
# Update depth visibility based on initial mode
|
|
211
|
+
self._update_depth_visibility()
|
|
212
|
+
|
|
213
|
+
return parent_frame
|
|
214
|
+
|
|
215
|
+
def _update_depth_visibility(self):
|
|
216
|
+
"""Show/hide depth spinbox based on recursion mode."""
|
|
217
|
+
if hasattr(self, 'depth_frame'):
|
|
218
|
+
if self.recursion_mode.get() == "limited":
|
|
219
|
+
self.depth_frame.pack(side='left', padx=(5, 0))
|
|
220
|
+
else:
|
|
221
|
+
self.depth_frame.pack_forget()
|
|
222
|
+
|
|
223
|
+
def _browse_input_folder(self):
|
|
224
|
+
"""Open folder browser for Input folder selection."""
|
|
225
|
+
folder = filedialog.askdirectory(title="Select Input Folder", parent=self.app)
|
|
226
|
+
if folder:
|
|
227
|
+
self.input_folder_var.set(folder)
|
|
228
|
+
self._save_all_settings()
|
|
229
|
+
|
|
230
|
+
def _browse_output_folder(self):
|
|
231
|
+
"""Open folder browser for Output folder selection."""
|
|
232
|
+
folder = filedialog.askdirectory(title="Select Output Folder", parent=self.app)
|
|
233
|
+
if folder:
|
|
234
|
+
self.output_folder_var.set(folder)
|
|
235
|
+
self._save_all_settings()
|
|
236
|
+
|
|
237
|
+
def _on_folder_changed(self):
|
|
238
|
+
"""Callback when folder paths change (typed or browsed)."""
|
|
239
|
+
# Debounce the save to avoid excessive writes when typing
|
|
240
|
+
if hasattr(self, '_save_timer'):
|
|
241
|
+
self.app.after_cancel(self._save_timer)
|
|
242
|
+
self._save_timer = self.app.after(1000, self._save_all_settings) # Save after 1 second of no changes
|
|
243
|
+
|
|
244
|
+
def _on_setting_changed(self):
|
|
245
|
+
"""Callback when any setting changes (checkboxes, radio buttons, etc)."""
|
|
246
|
+
# Debounce the save to avoid excessive writes
|
|
247
|
+
if hasattr(self, '_setting_save_timer'):
|
|
248
|
+
self.app.after_cancel(self._setting_save_timer)
|
|
249
|
+
self._setting_save_timer = self.app.after(500, self._save_all_settings) # Save after 0.5 seconds
|
|
250
|
+
|
|
251
|
+
def _save_all_settings(self):
|
|
252
|
+
"""Save all settings (folders, fields, options) when they change."""
|
|
253
|
+
if hasattr(self.app, 'settings') and hasattr(self.app, 'save_settings'):
|
|
254
|
+
# Update the settings
|
|
255
|
+
if "tool_settings" in self.app.settings:
|
|
256
|
+
if "Folder File Reporter" not in self.app.settings["tool_settings"]:
|
|
257
|
+
self.app.settings["tool_settings"]["Folder File Reporter"] = {}
|
|
258
|
+
|
|
259
|
+
# Save folder paths
|
|
260
|
+
self.app.settings["tool_settings"]["Folder File Reporter"]["last_input_folder"] = self.input_folder_var.get()
|
|
261
|
+
self.app.settings["tool_settings"]["Folder File Reporter"]["last_output_folder"] = self.output_folder_var.get()
|
|
262
|
+
|
|
263
|
+
# Save field selections
|
|
264
|
+
self.app.settings["tool_settings"]["Folder File Reporter"]["field_selections"] = {
|
|
265
|
+
field: var.get() for field, var in self.field_selections.items()
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# Save other options
|
|
269
|
+
self.app.settings["tool_settings"]["Folder File Reporter"]["separator"] = self.separator.get()
|
|
270
|
+
self.app.settings["tool_settings"]["Folder File Reporter"]["folders_only"] = self.folders_only.get()
|
|
271
|
+
self.app.settings["tool_settings"]["Folder File Reporter"]["recursion_mode"] = self.recursion_mode.get()
|
|
272
|
+
self.app.settings["tool_settings"]["Folder File Reporter"]["recursion_depth"] = self.recursion_depth.get()
|
|
273
|
+
self.app.settings["tool_settings"]["Folder File Reporter"]["size_format"] = self.size_format.get()
|
|
274
|
+
self.app.settings["tool_settings"]["Folder File Reporter"]["date_format"] = self.date_format.get()
|
|
275
|
+
|
|
276
|
+
# Save to file
|
|
277
|
+
self.app.save_settings()
|
|
278
|
+
|
|
279
|
+
def _generate_reports(self):
|
|
280
|
+
"""
|
|
281
|
+
Generate reports and write them to the active Input/Output tabs.
|
|
282
|
+
"""
|
|
283
|
+
input_folder = self.input_folder_var.get().strip()
|
|
284
|
+
output_folder = self.output_folder_var.get().strip()
|
|
285
|
+
|
|
286
|
+
if not input_folder and not output_folder:
|
|
287
|
+
if self.app.dialog_manager:
|
|
288
|
+
self.app.dialog_manager.show_warning(
|
|
289
|
+
"No Folders Selected",
|
|
290
|
+
"Please select at least one folder to generate a report."
|
|
291
|
+
)
|
|
292
|
+
else:
|
|
293
|
+
tk.messagebox.showwarning(
|
|
294
|
+
"No Folders Selected",
|
|
295
|
+
"Please select at least one folder to generate a report.",
|
|
296
|
+
parent=self.app
|
|
297
|
+
)
|
|
298
|
+
return
|
|
299
|
+
|
|
300
|
+
# Get active Input and Output text widgets
|
|
301
|
+
input_tab_index = self.app.input_notebook.index(self.app.input_notebook.select())
|
|
302
|
+
output_tab_index = self.app.output_notebook.index(self.app.output_notebook.select())
|
|
303
|
+
|
|
304
|
+
active_input_tab = self.app.input_tabs[input_tab_index]
|
|
305
|
+
active_output_tab = self.app.output_tabs[output_tab_index]
|
|
306
|
+
|
|
307
|
+
# Debug logging
|
|
308
|
+
if hasattr(self.app, 'logger') and self.app.logger:
|
|
309
|
+
self.app.logger.info(f"Active Input tab index: {input_tab_index}")
|
|
310
|
+
self.app.logger.info(f"Active Output tab index: {output_tab_index}")
|
|
311
|
+
self.app.logger.info(f"Input text widget: {active_input_tab.text}")
|
|
312
|
+
self.app.logger.info(f"Output text widget: {active_output_tab.text}")
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
# Create reporter WITHOUT calling _create_ui (which would create its own text widgets)
|
|
316
|
+
# We'll manually set up the reporter to use the main app's text widgets
|
|
317
|
+
reporter = FolderFileReporter.__new__(FolderFileReporter)
|
|
318
|
+
|
|
319
|
+
# Manually initialize the reporter without calling __init__ (which calls _create_ui)
|
|
320
|
+
reporter.parent = None # We don't need a parent since we're not creating UI
|
|
321
|
+
reporter.dialog_manager = self.app.dialog_manager
|
|
322
|
+
reporter.input_text_widget = active_input_tab.text
|
|
323
|
+
reporter.output_text_widget = active_output_tab.text
|
|
324
|
+
reporter.settings_file = "settings.json"
|
|
325
|
+
reporter.tool_key = "Folder File Reporter"
|
|
326
|
+
|
|
327
|
+
# Initialize UI variables
|
|
328
|
+
reporter.input_folder_path = tk.StringVar()
|
|
329
|
+
reporter.output_folder_path = tk.StringVar()
|
|
330
|
+
|
|
331
|
+
# Field selection variables
|
|
332
|
+
reporter.field_selections = {
|
|
333
|
+
'path': tk.BooleanVar(value=True),
|
|
334
|
+
'name': tk.BooleanVar(value=True),
|
|
335
|
+
'size': tk.BooleanVar(value=True),
|
|
336
|
+
'date_modified': tk.BooleanVar(value=True)
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
# Configuration variables
|
|
340
|
+
reporter.separator = tk.StringVar(value=" | ")
|
|
341
|
+
reporter.folders_only = tk.BooleanVar(value=False)
|
|
342
|
+
reporter.recursion_mode = tk.StringVar(value="full")
|
|
343
|
+
reporter.recursion_depth = tk.IntVar(value=2)
|
|
344
|
+
reporter.size_format = tk.StringVar(value="human")
|
|
345
|
+
reporter.date_format = tk.StringVar(value="%Y-%m-%d %H:%M:%S")
|
|
346
|
+
|
|
347
|
+
# Use the main app's text widgets directly
|
|
348
|
+
reporter.input_text = active_input_tab.text
|
|
349
|
+
reporter.output_text = active_output_tab.text
|
|
350
|
+
|
|
351
|
+
# Debug: Verify text widgets are set correctly
|
|
352
|
+
if hasattr(self.app, 'logger') and self.app.logger:
|
|
353
|
+
self.app.logger.info(f"Reporter input_text set to: {reporter.input_text}")
|
|
354
|
+
self.app.logger.info(f"Reporter output_text set to: {reporter.output_text}")
|
|
355
|
+
|
|
356
|
+
# CRITICAL: Enable output tab for writing (Pomera keeps output tabs disabled/read-only)
|
|
357
|
+
active_output_tab.text.config(state="normal")
|
|
358
|
+
|
|
359
|
+
# Set the folder paths
|
|
360
|
+
reporter.input_folder_path.set(input_folder)
|
|
361
|
+
reporter.output_folder_path.set(output_folder)
|
|
362
|
+
|
|
363
|
+
# Debug: Log folder paths
|
|
364
|
+
if hasattr(self.app, 'logger') and self.app.logger:
|
|
365
|
+
self.app.logger.info(f"Input folder path: {input_folder}")
|
|
366
|
+
self.app.logger.info(f"Output folder path: {output_folder}")
|
|
367
|
+
|
|
368
|
+
# Transfer all settings from adapter to reporter
|
|
369
|
+
for field, var in self.field_selections.items():
|
|
370
|
+
reporter.field_selections[field].set(var.get())
|
|
371
|
+
|
|
372
|
+
reporter.separator.set(self.separator.get())
|
|
373
|
+
reporter.folders_only.set(self.folders_only.get())
|
|
374
|
+
reporter.recursion_mode.set(self.recursion_mode.get())
|
|
375
|
+
reporter.recursion_depth.set(self.recursion_depth.get())
|
|
376
|
+
reporter.size_format.set(self.size_format.get())
|
|
377
|
+
reporter.date_format.set(self.date_format.get())
|
|
378
|
+
|
|
379
|
+
# Generate the reports
|
|
380
|
+
reporter.generate_report()
|
|
381
|
+
|
|
382
|
+
# Re-disable output tab to maintain Pomera's read-only convention
|
|
383
|
+
active_output_tab.text.config(state="disabled")
|
|
384
|
+
|
|
385
|
+
# Verify content was written
|
|
386
|
+
if hasattr(self.app, 'logger') and self.app.logger:
|
|
387
|
+
input_content = active_input_tab.text.get("1.0", "end-1c")
|
|
388
|
+
output_content = active_output_tab.text.get("1.0", "end-1c")
|
|
389
|
+
self.app.logger.info(f"Generated folder reports - Input: {input_folder}, Output: {output_folder}")
|
|
390
|
+
self.app.logger.info(f"Input tab content length: {len(input_content)} chars")
|
|
391
|
+
self.app.logger.info(f"Output tab content length: {len(output_content)} chars")
|
|
392
|
+
if input_content:
|
|
393
|
+
self.app.logger.info(f"Input tab first 100 chars: {input_content[:100]}")
|
|
394
|
+
if output_content:
|
|
395
|
+
self.app.logger.info(f"Output tab first 100 chars: {output_content[:100]}")
|
|
396
|
+
|
|
397
|
+
except Exception as e:
|
|
398
|
+
error_msg = f"Error generating reports: {e}"
|
|
399
|
+
self.app.logger.error(error_msg, exc_info=True)
|
|
400
|
+
if self.app.dialog_manager:
|
|
401
|
+
self.app.dialog_manager.show_error("Report Generation Error", error_msg)
|
|
402
|
+
else:
|
|
403
|
+
tk.messagebox.showerror("Report Generation Error", error_msg, parent=self.app)
|
|
404
|
+
|
|
405
|
+
def get_default_settings(self):
|
|
406
|
+
"""
|
|
407
|
+
Get default settings for the tool.
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
dict: Default settings
|
|
411
|
+
"""
|
|
412
|
+
return {
|
|
413
|
+
'last_input_folder': '',
|
|
414
|
+
'last_output_folder': '',
|
|
415
|
+
'field_selections': {
|
|
416
|
+
'path': True,
|
|
417
|
+
'name': True,
|
|
418
|
+
'size': True,
|
|
419
|
+
'date_modified': True
|
|
420
|
+
},
|
|
421
|
+
'separator': ' | ',
|
|
422
|
+
'folders_only': False,
|
|
423
|
+
'recursion_mode': 'full',
|
|
424
|
+
'recursion_depth': 2,
|
|
425
|
+
'size_format': 'human',
|
|
426
|
+
'date_format': '%Y-%m-%d %H:%M:%S'
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
def load_settings(self, settings):
|
|
430
|
+
"""
|
|
431
|
+
Load settings from the application settings.
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
settings: Dictionary of settings to load
|
|
435
|
+
"""
|
|
436
|
+
if 'last_input_folder' in settings:
|
|
437
|
+
self.input_folder_var.set(settings['last_input_folder'])
|
|
438
|
+
if 'last_output_folder' in settings:
|
|
439
|
+
self.output_folder_var.set(settings['last_output_folder'])
|
|
440
|
+
|
|
441
|
+
# Load field selections
|
|
442
|
+
if 'field_selections' in settings:
|
|
443
|
+
for field, value in settings['field_selections'].items():
|
|
444
|
+
if field in self.field_selections:
|
|
445
|
+
self.field_selections[field].set(value)
|
|
446
|
+
|
|
447
|
+
# Load other settings
|
|
448
|
+
if 'separator' in settings:
|
|
449
|
+
self.separator.set(settings['separator'])
|
|
450
|
+
if 'folders_only' in settings:
|
|
451
|
+
self.folders_only.set(settings['folders_only'])
|
|
452
|
+
if 'recursion_mode' in settings:
|
|
453
|
+
self.recursion_mode.set(settings['recursion_mode'])
|
|
454
|
+
if 'recursion_depth' in settings:
|
|
455
|
+
self.recursion_depth.set(settings['recursion_depth'])
|
|
456
|
+
if 'size_format' in settings:
|
|
457
|
+
self.size_format.set(settings['size_format'])
|
|
458
|
+
if 'date_format' in settings:
|
|
459
|
+
self.date_format.set(settings['date_format'])
|
|
460
|
+
|
|
461
|
+
def save_settings(self):
|
|
462
|
+
"""
|
|
463
|
+
Save current settings.
|
|
464
|
+
|
|
465
|
+
Returns:
|
|
466
|
+
dict: Current settings to save
|
|
467
|
+
"""
|
|
468
|
+
return {
|
|
469
|
+
'last_input_folder': self.input_folder_var.get(),
|
|
470
|
+
'last_output_folder': self.output_folder_var.get(),
|
|
471
|
+
'field_selections': {
|
|
472
|
+
field: var.get() for field, var in self.field_selections.items()
|
|
473
|
+
},
|
|
474
|
+
'separator': self.separator.get(),
|
|
475
|
+
'folders_only': self.folders_only.get(),
|
|
476
|
+
'recursion_mode': self.recursion_mode.get(),
|
|
477
|
+
'recursion_depth': self.recursion_depth.get(),
|
|
478
|
+
'size_format': self.size_format.get(),
|
|
479
|
+
'date_format': self.date_format.get()
|
|
480
|
+
}
|