Skip to content
Open
Show file tree
Hide file tree
Changes from 250 commits
Commits
Show all changes
462 commits
Select commit Hold shift + click to select a range
e62d67e
Split import into two lines.
jamescrake-merani Sep 9, 2024
e127495
Looks like a few names didn't change automatically
jamescrake-merani Sep 9, 2024
521d164
Double clicking a unit selects it.
jamescrake-merani Sep 9, 2024
e139150
Added an unload button.
jamescrake-merani Sep 9, 2024
00e6578
Use a horizontal layout.
jamescrake-merani Sep 9, 2024
18c384b
Handle case where there are no more files.
jamescrake-merani Sep 9, 2024
9cd1ac3
Disable table when there's no data.
jamescrake-merani Sep 9, 2024
b21d2de
Handle a unicode decode error.
jamescrake-merani Sep 9, 2024
4c9e490
Set filename label on update.
jamescrake-merani Sep 9, 2024
5f5958d
Reset the label back to original after unload.
jamescrake-merani Sep 9, 2024
03d34ab
For now, ignore the horizontal size hint.
jamescrake-merani Sep 9, 2024
409b4f6
Fixed error that sometimes happens when selecting.
jamescrake-merani Sep 9, 2024
f8e9f52
Disable the button when there's none to unload.
jamescrake-merani Sep 9, 2024
314de06
Set current filename to none when there is none.
jamescrake-merani Sep 10, 2024
d1f222b
Give a window title.
jamescrake-merani Sep 10, 2024
b355f0e
Added a done button.
jamescrake-merani Oct 21, 2024
4a5bfa8
Get the column tuple.
jamescrake-merani Oct 21, 2024
a028ad6
Make this a property.
jamescrake-merani Oct 21, 2024
a7ab5e8
Added exclude lines to match param in dataclass.
jamescrake-merani Oct 21, 2024
def0a6e
Fixed logic error.
jamescrake-merani Oct 21, 2024
43c22b7
Hook up the done button to an event.
jamescrake-merani Oct 21, 2024
c57d86b
Fixed slot connection.
jamescrake-merani Oct 21, 2024
13ab6d3
Ascii dialog is now a dialog not a widget.
jamescrake-merani Oct 21, 2024
ece282f
I don't think these comments are needed anymore.
jamescrake-merani Oct 21, 2024
cbca3af
Changed how the current unit is found.
jamescrake-merani Oct 21, 2024
a05c8fa
Include the selected unit in the options.
jamescrake-merani Oct 21, 2024
c308ee0
Accept when clicking the done button.
jamescrake-merani Oct 21, 2024
fcc9ae1
Need to call items in order to destructure.
jamescrake-merani Oct 21, 2024
bded22a
Just hard code the value.
jamescrake-merani Oct 21, 2024
4758ce5
Fix excluded_lines.
jamescrake-merani Oct 21, 2024
aaf1df4
Keep track of the full path.
jamescrake-merani Oct 21, 2024
a8fb897
Fix the params.
jamescrake-merani Oct 21, 2024
505e143
Load the data instead of printing params only.
jamescrake-merani Oct 21, 2024
a456692
Return the unit not the symbol.
jamescrake-merani Oct 22, 2024
d66f839
Send in an empty dict of metadata for now.
jamescrake-merani Oct 25, 2024
99ea5d4
Added an edit metadata button.
jamescrake-merani Oct 25, 2024
e79f2cc
Bring in the files for the metadata filename gui.
jamescrake-merani Oct 25, 2024
5510c05
Renamed file, and ade it a dialog.
jamescrake-merani Oct 25, 2024
6b4a19d
Forgot to commit new file.
jamescrake-merani Oct 25, 2024
5a5d6ce
Added save button.
jamescrake-merani Oct 25, 2024
8245d65
Hook up the save button to an event.
jamescrake-merani Oct 25, 2024
641e871
Print out the component metadata on success.
jamescrake-merani Oct 25, 2024
0ec32a8
Fixed imports.
jamescrake-merani Oct 25, 2024
c01413b
Add edit metadata button.
jamescrake-merani Oct 25, 2024
b3585b0
Fixed import.
jamescrake-merani Oct 25, 2024
f6d151b
Get filename from self.
jamescrake-merani Oct 25, 2024
598d96d
Created a property for the separator text.
jamescrake-merani Oct 25, 2024
2e174b4
Added a dict for separators.
jamescrake-merani Oct 25, 2024
daa8a1c
Take in initial values for these.
jamescrake-merani Oct 25, 2024
8b999dd
Set the separator field.
jamescrake-merani Oct 30, 2024
1329566
Pass in previous metadata, using defaults.
jamescrake-merani Nov 1, 2024
6917bc5
Selected components should persist.
jamescrake-merani Nov 1, 2024
2764215
Use the actual metadata.
jamescrake-merani Nov 1, 2024
972085c
Add widget for custom metadata entry.
jamescrake-merani Nov 1, 2024
be754d2
Changed name to be more consistent.
jamescrake-merani Nov 1, 2024
dbe0a04
Add a custom entry button to the layout.
jamescrake-merani Nov 1, 2024
1f1a2ee
Use a signal for when the custom button is pressed
jamescrake-merani Nov 1, 2024
a5de73e
Started with the selector widget.
jamescrake-merani Nov 6, 2024
de086fb
Hook up event handlers properly.
jamescrake-merani Nov 18, 2024
4706dfb
Use the generic selector widget.
jamescrake-merani Nov 21, 2024
91ced7b
Init the base class.
jamescrake-merani Nov 21, 2024
162ee2a
Forgot to pass self into layout.
jamescrake-merani Nov 21, 2024
fffac57
Handle when there is no new widget.
jamescrake-merani Nov 21, 2024
8f379b9
Use isinstance.
jamescrake-merani Nov 21, 2024
2763af0
Fixed event handling.
jamescrake-merani Nov 21, 2024
88e2985
Layout not inited properly.
jamescrake-merani Nov 21, 2024
6a59019
Need to delete, and reassign selector widget.
jamescrake-merani Nov 21, 2024
621b330
This line shouldn't be here.
jamescrake-merani Nov 21, 2024
3c509be
Set the title of the metadata dialog.
jamescrake-merani Nov 21, 2024
2d37744
Use separate functions for creating these widgets.
jamescrake-merani Nov 21, 2024
494040d
Use the new function.
jamescrake-merani Nov 21, 2024
84ca5c9
Removed comment that doesn't make sense anymore.
jamescrake-merani Nov 22, 2024
c2a4481
Handle value changes.
jamescrake-merani Nov 22, 2024
60f6c3f
Pass in the new args.
jamescrake-merani Nov 22, 2024
9740063
Fixed typos in comments.
jamescrake-merani Nov 22, 2024
5d7c340
Choose default widget based on current option.
jamescrake-merani Nov 22, 2024
ca46946
Set the field from the already set metadata.
jamescrake-merani Nov 22, 2024
be5de49
Wrong control.
jamescrake-merani Nov 22, 2024
24b9a41
Pass raw_metadata into params.
jamescrake-merani Nov 25, 2024
a95c46d
This should be a TODO comment.
jamescrake-merani Nov 25, 2024
9a19d02
Updated this map with a todo warning.
jamescrake-merani Nov 25, 2024
9ff4d5a
Gonna try a different approach.
jamescrake-merani Nov 25, 2024
09e0759
Fixed bug where not editing metadata wouldn't work
jamescrake-merani Nov 25, 2024
9f4d0de
Strip all of the lines.
jamescrake-merani Nov 26, 2024
f6e4214
First step towards a master metadata dictionary.
jamescrake-merani Nov 27, 2024
256d124
Pass along the master metadata dict.
jamescrake-merani Nov 28, 2024
4cc3a55
Pass in the master metadata.
jamescrake-merani Nov 28, 2024
ff2a170
Changed round a bunch of type hints.
jamescrake-merani Nov 28, 2024
1568867
Master metadata should be the same for all files.
jamescrake-merani Dec 2, 2024
13d82b7
Give the master metadata a default value.
jamescrake-merani Dec 2, 2024
17826bd
This should be type hinted.
jamescrake-merani Dec 2, 2024
3d0d9d2
Remove the metadata dict param.
jamescrake-merani Dec 2, 2024
2dd581e
I think these are the wrong way round.
jamescrake-merani Dec 2, 2024
67be830
Give the master metadata to metadata filename.
jamescrake-merani Dec 2, 2024
a8d6670
Create some classes for metadata.
jamescrake-merani Dec 2, 2024
9acab29
Remove unneeded import.
jamescrake-merani Dec 2, 2024
f67e460
Implemented get_metadata function.
jamescrake-merani Dec 2, 2024
0214d8f
Update metadata function.
jamescrake-merani Dec 2, 2024
a1eb9f4
Add defaults.
jamescrake-merani Dec 2, 2024
1a98295
Implemented add file function.
jamescrake-merani Dec 2, 2024
2b58b9f
Make default_categories not a method.
jamescrake-merani Dec 2, 2024
dc7ed0a
Changed the signature of get metadata.
jamescrake-merani Dec 2, 2024
2a8dea3
Start using the new internal metadata class.
jamescrake-merani Dec 2, 2024
51de209
Need to use factory for defaults.
jamescrake-merani Dec 2, 2024
7e48111
Add a separator field.
jamescrake-merani Dec 3, 2024
663b6ae
Don't need the separator argument anymore.
jamescrake-merani Dec 3, 2024
44e6a4f
Type hint to keep pyright happy.
jamescrake-merani Dec 3, 2024
559c4de
Some more argument fixes.
jamescrake-merani Dec 3, 2024
312e74d
Don't need the separator param.
jamescrake-merani Dec 3, 2024
6d5c3ad
Implemented clear_metadata function.
jamescrake-merani Dec 3, 2024
f9da54e
Component selector uses the new metadata class.
jamescrake-merani Dec 3, 2024
0843a99
Get the filename components in the class itself.
jamescrake-merani Dec 3, 2024
7a704ce
Replicate the behaviour of the old system.
jamescrake-merani Dec 3, 2024
f74aa3d
Updated the clear metadata function.
jamescrake-merani Dec 3, 2024
a7d6664
Update for internal metadata.
jamescrake-merani Dec 3, 2024
e7cbe2c
Use new params.
jamescrake-merani Dec 3, 2024
5fa54f6
Make sure a separator is initialised.
jamescrake-merani Dec 3, 2024
abf84e1
Use the name load file.
jamescrake-merani Dec 3, 2024
fc07e31
Need to add file to metadata when loaded.
jamescrake-merani Dec 3, 2024
a4496b6
Forgot to add these :P
jamescrake-merani Dec 3, 2024
5da7cef
Remove old draw options call.
jamescrake-merani Dec 3, 2024
9b8e4fb
Missing else.
jamescrake-merani Dec 3, 2024
3b55c2a
Pull out the new internal metadata.
jamescrake-merani Dec 3, 2024
5870223
Don't need this comment.
jamescrake-merani Dec 3, 2024
350e813
Take into account this is now a list.
jamescrake-merani Dec 4, 2024
4d8fd9a
Use the replaced class from sasdata.
jamescrake-merani Dec 4, 2024
d505517
Whoops forgot to save these files.
jamescrake-merani Dec 4, 2024
51dda75
Forgot to remove old import.
jamescrake-merani Dec 4, 2024
723e886
Use the new params.
jamescrake-merani Dec 4, 2024
bf25ae3
Send the full file path.
jamescrake-merani Dec 4, 2024
ea6765a
Should only split in metadata class.
jamescrake-merani Dec 4, 2024
d00cb5a
Default separator should be set in dialog.py
jamescrake-merani Dec 4, 2024
58b60b7
Load multiple files at the same time.
jamescrake-merani Dec 6, 2024
033d69f
Updated name to avoid conflict with QT function.
jamescrake-merani Dec 9, 2024
a0a9784
Added type hints.
jamescrake-merani Dec 9, 2024
0014226
Add unparasable lines to warning label.
jamescrake-merani Dec 9, 2024
83f30e5
Take into account the startpos.
jamescrake-merani Dec 9, 2024
3239f18
Update warning label is a function.
jamescrake-merani Dec 9, 2024
65e3e4a
Call new function when its needed.
jamescrake-merani Dec 9, 2024
2086a44
Forgot to save :P
jamescrake-merani Dec 9, 2024
5766718
Fixed how lines are counted.
jamescrake-merani Dec 9, 2024
1319bf0
Try an orange font for this.
jamescrake-merani Dec 9, 2024
cee9027
Type hint to stop pyright from complaining.
jamescrake-merani Dec 10, 2024
fd3953e
Don't pass the CSV if there isn't one.
jamescrake-merani Dec 10, 2024
a3870e2
Separate this into another file.
jamescrake-merani Dec 10, 2024
f74f96d
Fixed a crash when we have > 1000 rows.
jamescrake-merani Dec 10, 2024
5ff7533
Started implementing default units.
jamescrake-merani Dec 10, 2024
20516e8
Use the new preferred units.
jamescrake-merani Dec 10, 2024
76e378b
Add some radios for choosing what to separate on.
jamescrake-merani Dec 11, 2024
133ffb0
Default to using the character.
jamescrake-merani Dec 11, 2024
6fcfdee
Use a separate propety for the expression.
jamescrake-merani Dec 11, 2024
bbeb2da
Split on casing as well.
jamescrake-merani Dec 11, 2024
255cbc9
Use new constant for casing regex.
jamescrake-merani Dec 11, 2024
7cc1530
Try hooking up to this event.
jamescrake-merani Dec 11, 2024
8cd3b91
We should probably use our internal split function.
jamescrake-merani Dec 11, 2024
378e791
Fixed regex.
jamescrake-merani Dec 11, 2024
e6d713b
Was using the wrong event.
jamescrake-merani Dec 11, 2024
268ae43
Changed where options is generated.
jamescrake-merani Dec 11, 2024
c36b2fe
Need to set this earlier to stop the event firing
jamescrake-merani Dec 11, 2024
91dbcb5
This shouldn't be here anymore.
jamescrake-merani Dec 11, 2024
4f49df2
These functions aren't needed anymore.
jamescrake-merani Dec 11, 2024
dfbe18c
Update the separator before updating stuff.
jamescrake-merani Dec 11, 2024
e78c89d
Call purge unreachable on separator update.
jamescrake-merani Dec 12, 2024
3b50828
Disable the separator box if casing is enabled.
jamescrake-merani Dec 12, 2024
308fd0e
Return unformatted if we're using casing separation.
jamescrake-merani Dec 12, 2024
3450780
Fixed error when there are no capital letters.
jamescrake-merani Dec 12, 2024
8cb16c5
Use a property for starting pos.
jamescrake-merani Dec 12, 2024
f9857c4
Update warning on selection/deselection.
jamescrake-merani Dec 12, 2024
650b05f
Add a setter for the current unit.
jamescrake-merani Dec 12, 2024
f8fa870
Make sure units match on uncertanties.
jamescrake-merani Dec 12, 2024
b620a27
Trigger column changed when the unit changes.
jamescrake-merani Dec 12, 2024
6ff1421
Stop event triggering when unit is empty.
jamescrake-merani Dec 12, 2024
333ca8f
Make sure ALL the columns are numbers.
jamescrake-merani Dec 13, 2024
0eee5bf
Use the new init separator method for the metadata.
jamescrake-merani Dec 13, 2024
c4e3ee6
Add dev menu
lucas-wilkins Jul 30, 2024
cce2198
Make menu show when config setting made
lucas-wilkins Jul 30, 2024
f739db1
Should just be using split line from the reader.
jamescrake-merani Dec 18, 2024
d104f2c
Shouldn't be calling items here.
jamescrake-merani Dec 18, 2024
521c076
Convert to list to make the interpreter happy.
jamescrake-merani Dec 18, 2024
a527bbe
This isn't true anymore.
jamescrake-merani Dec 18, 2024
620e01f
Type hinting to stop linting from complaining.
jamescrake-merani Jan 8, 2025
91a2b42
Changed the params for the new order.
jamescrake-merani Jan 8, 2025
d8beb42
Updated order again.
jamescrake-merani Jan 8, 2025
4f1c916
Changed order yet again.
jamescrake-merani Jan 8, 2025
fade71b
Add logic from starting the ascii reader from dev.
jamescrake-merani Jan 15, 2025
5d34467
Don't use relative module paths.
jamescrake-merani Jan 15, 2025
df4ce6f
Got rid of filename label, and move edit metadata.
jamescrake-merani Jan 28, 2025
5a1506c
Rename load file to select file.
jamescrake-merani Jan 28, 2025
603ad77
Add a cancel button.
jamescrake-merani Jan 28, 2025
67a7c1d
Disbale units when column is ignored.
jamescrake-merani Jan 28, 2025
9765f47
Centre the checkbox and remove label.
jamescrake-merani Jan 28, 2025
af0a3ef
Try this for clearer.
jamescrake-merani Jan 28, 2025
4c528f6
Maybe lets just empty the message.
jamescrake-merani Jan 28, 2025
79c8b22
Implement set checked method as well.
jamescrake-merani Jan 28, 2025
29a8d3b
Didn't call method properly.
jamescrake-merani Jan 28, 2025
c1346ff
Add type hinting here.
jamescrake-merani Jan 28, 2025
f1189ea
Try this for resetting the foreground color.
jamescrake-merani Jan 28, 2025
dec8dc7
Fixed import.
jamescrake-merani Jan 28, 2025
7e2bfa4
Use Lucas' mode idea for the column count.
jamescrake-merani Jan 28, 2025
557dc00
Put unload, and the filename on same line.
jamescrake-merani Jan 29, 2025
b32509b
Changed the bottom row.
jamescrake-merani Jan 30, 2025
8e14c28
Fixed indentation mistake in guess.
jamescrake-merani Jan 30, 2025
1fc3d3c
Changed how symbols are ignored.
jamescrake-merani Jan 30, 2025
0c9fdc3
Add pluses to the symbols.
jamescrake-merani Jan 30, 2025
6507aab
SasData should keep the metadata categories.
jamescrake-merani Feb 24, 2025
b37f8bb
Updated units.
jamescrake-merani Feb 10, 2025
d4c4386
Remove this comment.
jamescrake-merani Feb 10, 2025
2e8e9b6
Remove fixme comment.
jamescrake-merani Feb 10, 2025
2be801f
Try this?
jamescrake-merani Feb 10, 2025
8474a58
Making casing consistent.
jamescrake-merani Feb 10, 2025
9ec2cce
Remove guess from the SasView repository.
jamescrake-merani Feb 12, 2025
f184ebc
Update import.
jamescrake-merani Feb 12, 2025
135ad2b
Init should probably be at the top.
jamescrake-merani Feb 12, 2025
c02e482
Move this logic into SasData.
jamescrake-merani Feb 12, 2025
f5dae93
Removed the old import.
jamescrake-merani Feb 12, 2025
68b3b95
Import the right function.
jamescrake-merani Feb 12, 2025
5504112
Handle ignored columns.
jamescrake-merani Feb 13, 2025
323fa23
Fixed crashes when a filename just using casing.
jamescrake-merani Feb 14, 2025
0e7379f
Removed unneeded emit call.
jamescrake-merani Feb 17, 2025
9e1d09c
Use the bidrectional pairings.
jamescrake-merani Feb 17, 2025
9fbcd3e
Fixes linting errors
DrPaulSharp Aug 13, 2025
20592d5
Fixes build
DrPaulSharp Aug 13, 2025
0ec38a1
initial commit
rozyczko Mar 15, 2026
e2e5f91
integration into FittingWidget
rozyczko Mar 15, 2026
cdf76de
added test for integration
rozyczko Mar 15, 2026
1963078
connect ui to the operations in the fitting tabs
rozyczko Mar 16, 2026
8aadce3
added tab to the preferences for undo depth parameter
rozyczko Mar 16, 2026
765b52e
ruff
rozyczko Mar 16, 2026
1879104
more ruff
rozyczko Mar 16, 2026
961143a
fixed for unnecessary undo firing on model load
rozyczko Mar 17, 2026
6dbabb1
Merge branch 'refactor_24' into undo_project
rozyczko Mar 18, 2026
791b08a
Merge branch 'main' into undo_project
rozyczko Jun 3, 2026
1f32c1a
added other perspectives
rozyczko Jun 4, 2026
fe5cd36
ruff
rozyczko Jun 4, 2026
b407d6f
minor fixes
rozyczko Jun 4, 2026
64c9878
more fixes
rozyczko Jun 4, 2026
6b6c0b3
fixed unit tests
rozyczko Jun 4, 2026
84a80fc
fixed another test
rozyczko Jun 4, 2026
a8322b0
minor fixes
rozyczko Jun 4, 2026
42dbc22
Merge branch 'main' into undo_project
rozyczko Jun 5, 2026
8dac130
added docs on undo/redo
rozyczko Jun 5, 2026
a0cd45a
PR review
rozyczko Jun 5, 2026
72f5aa7
fixes for corfunc and batch fitting
rozyczko Jun 5, 2026
9f48b31
reparent with main branch of sasdata
rozyczko Jun 8, 2026
25dec3e
added undo of the fitting, as implemented in undo_redo_24
rozyczko Jun 8, 2026
2374401
fixed PR comments
rozyczko Jun 19, 2026
b940a9f
fixes broken Undo contract for ParameterValueCommand and ParameterMin…
rozyczko Jun 19, 2026
310642c
Merge branch 'main' into undo_project
rozyczko Aug 21, 2026
a799230
fix failing tests
rozyczko Aug 21, 2026
97c402f
Merge branch 'main' into undo_project
rozyczko Aug 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build_tools/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ zope
requests

# Alphabetized list of OS-specific packages
pywin32; platform_system == "Windows"
pywin32; platform_system == "Windows"
4 changes: 4 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import os
import platform

# Must be set before any Qt or matplotlib import so that matplotlib's
# qt_compat.py selects PySide6 instead of raising an ImportError.
os.environ.setdefault("QT_API", "pyside6")

import pytest

# Run the tests in offscreen mode
Expand Down
26 changes: 26 additions & 0 deletions docs/sphinx-docs/source/user/menu_bar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,38 @@ Edit
----
The Edit option allows you to:

- undo the most recent parameter change (``Ctrl+Z``);
- redo a previously undone parameter change (``Ctrl+Y``);
- copy and paste parameters between *SasView* analysis windows;
- copy parameters from a *SasView* analysis window to the Clipboard as either tab-delimited text (compatible with Microsoft Excel) or LaTex-wrapped text;
- generate a summary 'Report' of the most recent analysis performed;
- reset parameter values in the P(r) Inversion analysis page;
- freeze/copy fit results as separate data sets.

The **Undo** and **Redo** commands are also available as buttons in the
main toolbar, and their tooltips dynamically show which action will be
reverted (e.g. "Undo Change radius").

Undo/Redo is supported in the following perspectives:

- **Model Fitting** – parameter changes in individual fit pages;
- **P(r) Inversion** – parameter changes in each inversion page;
- **Invariant** – parameter changes in the invariant calculator;
- **Size Distribution** – parameter changes in the size distribution
calculator;
- **Correlation Function** – parameter changes in the correlation
function analysis.

Each tab or page maintains its own independent undo history, so
switching between perspectives or fit pages preserves the undo/redo
state of each. The default history depth is 200 actions per tab,
configurable via the ``UNDO_STACK_MAX_DEPTH`` setting in
:file:`src/sas/system/config/config.py`.

.. note:: Undo/Redo is automatically suppressed during programmatic
operations such as loading a project or applying fit results,
to prevent spurious entries from cluttering the undo history.

View
----
The View option allows you to:
Expand Down
3 changes: 0 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ requires = [
"periodictable",
"pyopengl",
"pyside6",
"qtconsole",
"scipy",
Comment thread
rozyczko marked this conversation as resolved.
"superqt",
"sasdata",
"sasmodels",
"twisted",
Expand Down
89 changes: 89 additions & 0 deletions src/ascii_dialog/col_editor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from typing import cast

from PySide6.QtCore import Signal, Slot
from PySide6.QtWidgets import QHBoxLayout, QWidget

from sasdata.ascii_reader_metadata import bidirectional_pairings
from sasdata.quantities.units import NamedUnit

from ascii_dialog.column_unit import ColumnUnit


class ColEditor(QWidget):
"""An editor widget which allows the user to specify the columns of the data
from a set of options based on which dataset type has been selected."""
column_changed = Signal()

def __init__(self, cols: int, options: list[str]):
super().__init__()

self.cols = cols
self.options = options
self.layout = QHBoxLayout(self)
self.option_widgets: list[ColumnUnit] = []
for _ in range(cols):
new_widget = ColumnUnit(self.options)
new_widget.column_changed.connect(self.onColumnUpdate)
self.layout.addWidget(new_widget)
self.option_widgets.append(new_widget)

@Slot()
def onColumnUpdate(self):
column_changed = cast(ColumnUnit, self.sender())
pairing = bidirectional_pairings.get(column_changed.currentColumn)
if pairing is not None:
for col_unit in self.option_widgets:
# Second condition is important because otherwise, this event will keep being called, and the GUI will
# go into an infinite loop.
if col_unit.currentColumn == pairing and col_unit.currentUnit != column_changed.currentUnit:
col_unit.currentUnit = column_changed.currentUnit

def setCols(self, new_cols: int):
"""Set the amount of columns for the user to edit."""

# Decides whether we need to extend the current set of combo boxes, or
# remove some.
if self.cols < new_cols:
for _ in range(new_cols - self.cols):
new_widget = ColumnUnit(self.options)
new_widget.column_changed.connect(self.onColumnUpdate)
self.layout.addWidget(new_widget)
self.option_widgets.append(new_widget)

self.cols = new_cols
if self.cols > new_cols:
excess_cols = self.cols - new_cols
length = len(self.option_widgets)
excess_combo_boxes = self.option_widgets[length - excess_cols:length]
for box in excess_combo_boxes:
self.layout.removeWidget(box)
box.setParent(None)
self.option_widgets = self.option_widgets[0:length - excess_cols]
self.cols = new_cols
self.column_changed.emit()

def setColOrder(self, cols: list[str]):
"""Sets the series of currently selected columns to be cols, in that
order. If there are not enough column widgets include as many of the
columns in cols as possible.

"""
try:
for i, col_name in enumerate(cols):
self.option_widgets[i].setCurrentColumn(col_name)
except IndexError:
pass # Can ignore because it means we've run out of widgets.

def colNames(self) -> list[str]:
"""Get a list of all of the currently selected columns."""
return [widget.currentColumn for widget in self.option_widgets]

@property
def columns(self) -> list[tuple[str, NamedUnit | None]]:
return [(widget.currentColumn, widget.currentUnit if widget.currentColumn != "<ignore>" else None) for widget in self.option_widgets]

def replaceOptions(self, new_options: list[str]) -> None:
"""Replace options from which the user can choose for each column."""
self.options = new_options
for widget in self.option_widgets:
widget.replaceOptions(new_options)
128 changes: 128 additions & 0 deletions src/ascii_dialog/column_unit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env python3

from PySide6.QtCore import Signal, Slot
from PySide6.QtGui import QRegularExpressionValidator
from PySide6.QtWidgets import QComboBox, QHBoxLayout, QSizePolicy, QWidget

from sasdata.dataset_types import unit_kinds
from sasdata.default_units import defaults_or_fallback
from sasdata.quantities.units import NamedUnit

from ascii_dialog.unit_selector import UnitSelector


def configure_size_policy(combo_box: QComboBox) -> None:
policy = combo_box.sizePolicy()
policy.setHorizontalPolicy(QSizePolicy.Policy.Ignored)
combo_box.setSizePolicy(policy)

class ColumnUnit(QWidget):
"""Widget with 2 combo boxes: one allowing the user to pick a column, and
another to specify the units for that column."""
def __init__(self, options) -> None:
super().__init__()
self.col_widget = self.createColComboBox(options)
self.unit_widget = self.createUnitComboBox(self.col_widget.currentText())
self.layout = QHBoxLayout(self)
self.layout.addWidget(self.col_widget)
self.layout.addWidget(self.unit_widget)
self.current_option: str

column_changed = Signal()

def createColComboBox(self, options: list[str]) -> QComboBox:
"""Create the combo box for specifying the column based on the given
options."""
new_combo_box = QComboBox()
configure_size_policy(new_combo_box)
for option in options:
new_combo_box.addItem(option)
new_combo_box.setEditable(True)
validator = QRegularExpressionValidator(r"[a-zA-Z0-9]+")
new_combo_box.setValidator(validator)
new_combo_box.currentTextChanged.connect(self.onOptionChange)
return new_combo_box

def createUnitComboBox(self, selected_option: str) -> QComboBox:
"""Create the combo box for specifying the unit for selected_option"""
new_combo_box = QComboBox()
configure_size_policy(new_combo_box)
new_combo_box.setEditable(True)
self.updateUnits(new_combo_box, selected_option)
new_combo_box.currentTextChanged.connect(self.onUnitChange)
return new_combo_box

def updateUnits(self, unit_box: QComboBox, selected_option: str):
unit_box.clear()
self.current_option = selected_option
# Use the list of preferred units but fallback to the first 5 if there aren't any for this particular column.
if self.current_option == '<ignore>':
unit_box.setDisabled(True)
else:
unit_box.setDisabled(False)
unit_options = defaults_or_fallback(self.current_option)
option_symbols = [unit.symbol for unit in unit_options]
for option in option_symbols[:5]:
unit_box.addItem(option)
unit_box.addItem('Select More')


def replaceOptions(self, new_options) -> None:
"""Replace the old options for the column with new_options"""
self.col_widget.clear()
self.col_widget.addItems(new_options)

def setCurrentColumn(self, new_column_value: str) -> None:
"""Change the current selected column to new_column_value"""
self.col_widget.setCurrentText(new_column_value)
self.updateUnits(self.unit_widget, new_column_value)


@Slot()
def onOptionChange(self):
# If the new option is empty string, its probably because the current
# options have been removed. Can safely ignore this.
self.column_changed.emit()
new_option = self.col_widget.currentText()
if new_option == '':
return
try:
self.updateUnits(self.unit_widget, new_option)
except KeyError:
# Means the units for this column aren't known. This shouldn't be
# the case in the real version so for now we'll just clear the unit
# widget.
self.unit_widget.clear()

@Slot()
def onUnitChange(self):
new_text = self.unit_widget.currentText()
if new_text == 'Select More':
selector = UnitSelector(unit_kinds[self.col_widget.currentText()].name, False)
selector.exec()
# We need the selection unit in the list of options, or else QT has some dodgy behaviour.
self.unit_widget.insertItem(-1, selector.selected_unit.symbol)
self.unit_widget.setCurrentText(selector.selected_unit.symbol)
# This event could get triggered when the units have just been cleared, and not actually updated. We don't want
# to trigger it in this case.
elif not new_text == '':
self.column_changed.emit()

@property
def currentColumn(self):
"""The currently selected column."""
return self.col_widget.currentText()

@property
def currentUnit(self) -> NamedUnit:
"""The currently selected unit."""
current_unit_symbol = self.unit_widget.currentText()
for unit in unit_kinds[self.current_option].units:
if current_unit_symbol == unit.symbol:
return unit
# This error shouldn't really happen so if it does, it indicates there is a bug in the code.
raise ValueError("Current unit doesn't seem to exist")

@currentUnit.setter
def currentUnit(self, new_value: NamedUnit):
self.unit_widget.setCurrentText(new_value.symbol)
5 changes: 5 additions & 0 deletions src/ascii_dialog/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env python


TABLE_MAX_ROWS = 1000
NOFILE_TEXT = "Click the button below to load a file."
Loading
Loading