Skip to content

feat: add workspace functionality with manager and UI integration#3

Closed
Xcesius wants to merge 1 commit intomainfrom
feat/workspace-v1
Closed

feat: add workspace functionality with manager and UI integration#3
Xcesius wants to merge 1 commit intomainfrom
feat/workspace-v1

Conversation

@Xcesius
Copy link
Copy Markdown
Owner

@Xcesius Xcesius commented Aug 24, 2025

No description provided.

Copilot AI review requested due to automatic review settings August 24, 2025 21:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces comprehensive workspace functionality with a tabbed editor interface, replacing the single-view approach with a multi-file workspace system. The implementation includes workspace management for saving/loading application states, a file panel for quick navigation, and enhanced UI layout with tabbed editing.

Key changes:

  • Added workspace save/load/delete functionality with persistent JSON storage
  • Replaced single table view with tabbed editor interface supporting multiple open files
  • Added workspace file panel with drag-and-drop support for file management

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
workspaces.json Configuration file storing saved workspace states with window geometry and view settings
workspace_manager.py Core workspace management class providing JSON-based persistence for workspace snapshots
ui.py Major UI overhaul replacing single table with tabbed interface, workspace panel, and multi-file support
main_v2.py Added Qt logging filters to suppress debug noise during development
custom_widgets.py Enhanced table views with better editor ownership tracking and debug capabilities
config.json Updated configuration with new workspace settings and file tracking

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread workspaces.json
Comment on lines +33 to +139
"column_widths": [
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100
],
Copy link

Copilot AI Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The column_widths array contains 105 repeated values of 100. This repetitive data suggests the array could be replaced with a more compact representation like {count: 105, width: 100} or dynamically generated default values to improve maintainability.

Suggested change
"column_widths": [
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100,
100
],
"column_widths": {
"count": 105,
"width": 100
},

Copilot uses AI. Check for mistakes.
Comment thread ui.py
Comment on lines +35 to +36
except Exception:
pass
Copy link

Copilot AI Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The broad exception handling with bare 'except Exception:' and 'pass' suppresses all errors including programming errors. Consider logging the exception or handling specific exception types that are expected during normal operation.

Suggested change
except Exception:
pass
except Exception as e:
logging.exception("Failed to set _d2te_index property on editor in ComboBoxDelegate.createEditor")

Copilot uses AI. Check for mistakes.
Comment thread ui.py
Comment on lines +1118 to 1120
# Load the first selected into the editor
self._load_file_path(paths[0])

Copy link

Copilot AI Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method silently loads only the first file when multiple files are selected (line 1119), which may be unexpected behavior for users. Consider either loading all selected files in tabs or clearly indicating in the UI that only the first file will be opened.

Suggested change
# Load the first selected into the editor
self._load_file_path(paths[0])
# Load all selected files into the editor (in tabs)
for file_path in paths:
self._load_file_path(file_path)

Copilot uses AI. Check for mistakes.
Comment thread ui.py
Comment on lines +927 to +959

def on_tab_bar_clicked(self, index: int):
# Try to finalize edits in the current tab before switching
self._close_all_active_editors()

def _close_all_active_editors(self):
try:
from PyQt6.QtWidgets import QApplication
# Prefer closing the currently focused inline editor only; this avoids cross-view commits
fw = QApplication.focusWidget()
if fw is not None:
# Find owning QTableView and top-level editor widget
from PyQt6.QtWidgets import QTableView, QComboBox, QLineEdit, QSpinBox, QDoubleSpinBox, QDateEdit, QTimeEdit, QDateTimeEdit
editor_types = (QComboBox, QLineEdit, QSpinBox, QDoubleSpinBox, QDateEdit, QTimeEdit, QDateTimeEdit)
# Ascend from focus widget to find top-level editor
ed = fw
top_editor = None
depth = 0
while ed is not None and depth < 10: # Increased depth
if isinstance(ed, editor_types):
top_editor = ed
ed = ed.parent()
depth += 1
# If focus was inside editable combobox, use the combobox itself
if isinstance(top_editor, QLineEdit) and isinstance(top_editor.parent(), QComboBox):
top_editor = top_editor.parent()

# More thorough search for owning view - check all known table views
owner_view = None
all_views = list(self._tabs.values())
if hasattr(self, 'tableView') and self.tableView is not None:
all_views.append(self.tableView)

Copy link

Copilot AI Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method imports QApplication inside the function and performs complex widget hierarchy traversal on every call. Consider moving the import to the module level and caching widget references to improve performance, especially since this method may be called frequently during tab switching.

Suggested change
def on_tab_bar_clicked(self, index: int):
# Try to finalize edits in the current tab before switching
self._close_all_active_editors()
def _close_all_active_editors(self):
try:
from PyQt6.QtWidgets import QApplication
# Prefer closing the currently focused inline editor only; this avoids cross-view commits
fw = QApplication.focusWidget()
if fw is not None:
# Find owning QTableView and top-level editor widget
from PyQt6.QtWidgets import QTableView, QComboBox, QLineEdit, QSpinBox, QDoubleSpinBox, QDateEdit, QTimeEdit, QDateTimeEdit
editor_types = (QComboBox, QLineEdit, QSpinBox, QDoubleSpinBox, QDateEdit, QTimeEdit, QDateTimeEdit)
# Ascend from focus widget to find top-level editor
ed = fw
top_editor = None
depth = 0
while ed is not None and depth < 10: # Increased depth
if isinstance(ed, editor_types):
top_editor = ed
ed = ed.parent()
depth += 1
# If focus was inside editable combobox, use the combobox itself
if isinstance(top_editor, QLineEdit) and isinstance(top_editor.parent(), QComboBox):
top_editor = top_editor.parent()
# More thorough search for owning view - check all known table views
owner_view = None
all_views = list(self._tabs.values())
if hasattr(self, 'tableView') and self.tableView is not None:
all_views.append(self.tableView)
# Update cached views after tab change
self._update_all_views_cache()
def on_tab_bar_clicked(self, index: int):
# Try to finalize edits in the current tab before switching
self._close_all_active_editors()
def _update_all_views_cache(self):
# Cache all known table views for performance
self._all_views_cache = list(self._tabs.values())
if hasattr(self, 'tableView') and self.tableView is not None:
if self.tableView not in self._all_views_cache:
self._all_views_cache.append(self.tableView)
def _close_all_active_editors(self):
try:
# Prefer closing the currently focused inline editor only; this avoids cross-view commits
fw = QApplication.focusWidget()
if fw is not None:
# Find owning QTableView and top-level editor widget
# Ascend from focus widget to find top-level editor
ed = fw
top_editor = None
depth = 0
while ed is not None and depth < 10: # Increased depth
if isinstance(ed, EDITOR_WIDGET_TYPES):
top_editor = ed
ed = ed.parent()
depth += 1
# If focus was inside editable combobox, use the combobox itself
if isinstance(top_editor, QLineEdit) and isinstance(top_editor.parent(), QComboBox):
top_editor = top_editor.parent()
# More thorough search for owning view - check all known table views
owner_view = None
all_views = getattr(self, '_all_views_cache', list(self._tabs.values()))

Copilot uses AI. Check for mistakes.
Comment thread custom_widgets.py
Comment on lines +776 to +780
debug_on = False
try:
debug_on = self.config_manager.get_setting("debug_mode_enabled", False)
except Exception:
debug_on = False
Copy link

Copilot AI Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nested try-catch blocks for retrieving debug settings create unnecessary complexity. Consider extracting this debug flag retrieval into a helper method since it's used multiple times throughout the class.

Suggested change
debug_on = False
try:
debug_on = self.config_manager.get_setting("debug_mode_enabled", False)
except Exception:
debug_on = False
debug_on = self._is_debug_enabled()

Copilot uses AI. Check for mistakes.
Comment thread custom_widgets.py
Comment on lines +122 to +124
except Exception:
view = None
parent_to_use = parent
Copy link

Copilot AI Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The broad exception handling suppresses all exceptions including potential programming errors. Consider handling specific exceptions like AttributeError that might occur during normal operation, and logging unexpected exceptions for debugging.

Suggested change
except Exception:
view = None
parent_to_use = parent
except (AttributeError, TypeError):
view = None
parent_to_use = parent
except Exception as e:
print(f"[ERROR] Unexpected exception in createEditor parent determination: {e}")
view = None
parent_to_use = parent

Copilot uses AI. Check for mistakes.
@Xcesius Xcesius closed this Aug 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants