@@ -689,27 +689,32 @@ def _source_key(self, ti3: Path) -> tuple:
689689 return ("dir" , str (ti3 .parent ))
690690 return ("file" , str (ti3 ))
691691
692- def _append_source (self , ti3 : Path ) -> bool :
692+ def _append_source (self , ti3 : Path , origin : "Path | None" = None ) -> bool :
693693 """Add one measurement to the source list (no repaint). Returns False if it
694694 is already present or has no runs. Raises on a gather error, so a batch add
695- can report which files failed."""
695+ can report which files failed.
696+
697+ *origin* is the file the user actually picked (the same as *ti3* for a
698+ ChromIQ .ti3, but the original .mxf/.txt/.cxf when *ti3* is a temp
699+ conversion). The report is saved next to the origin, never the temp folder
700+ (Knut)."""
696701 key = self ._source_key (ti3 )
697702 if any (s .get ("key" ) == key for s in self ._sources ):
698703 return False
699704 name , runs = self ._gather_runs (ti3 )
700705 if not runs :
701706 return False
702707 self ._sources .append ({"key" : key , "name" : name , "dir" : ti3 .parent ,
703- "ti3" : ti3 , "runs" : runs })
708+ "ti3" : ti3 , "origin" : Path ( origin or ti3 ), " runs" : runs })
704709 if self ._ti3 is None :
705710 self ._ti3 = ti3
706711 return True
707712
708- def _add_source (self , ti3 : Path ) -> None :
713+ def _add_source (self , ti3 : Path , origin : "Path | None" = None ) -> None :
709714 """Add a single measurement and repaint (used when opening the report on
710715 one file)."""
711716 try :
712- added = self ._append_source (ti3 )
717+ added = self ._append_source (ti3 , origin )
713718 except Exception as exc : # noqa: BLE001
714719 self ._view .setHtml (self ._error_html (str (exc )))
715720 return
@@ -755,7 +760,7 @@ def _on_add_project(self) -> None:
755760 added , failed = 0 , []
756761 for path in paths :
757762 try :
758- if self ._append_source (self ._as_ti3 (Path (path ))):
763+ if self ._append_source (self ._as_ti3 (Path (path )), origin = Path ( path ) ):
759764 added += 1
760765 except Exception as exc : # noqa: BLE001
761766 failed .append (f"{ Path (path ).name } — { exc } " )
@@ -848,21 +853,31 @@ def _trend_configs(self) -> list:
848853 corner_metrics , None , 1 , False ),
849854 ]
850855
856+ def _anchor_dir (self ) -> Path :
857+ """The folder the PDF and Reveal default to: the folder of the FIRST
858+ source's ORIGINAL file — a ChromIQ run folder, or the user's own folder for
859+ an imported measurement — never the temp folder an i1Profiler file is
860+ converted into (Knut)."""
861+ if self ._sources :
862+ return self ._sources [0 ]["origin" ].parent
863+ return self ._ti3 .parent if self ._ti3 else Path .cwd ()
864+
851865 def _profile_root (self ) -> Path :
852866 """The profile's project folder (``<project>/runs/<id>`` → ``<project>``),
853- or the run folder itself for a browsed external ``.ti3`` that isn't in a
867+ or the folder itself for a browsed/imported measurement that isn't in a
854868 ChromIQ project layout."""
855- run_dir = self ._ti3 . parent if self . _ti3 else Path . cwd ()
869+ run_dir = self ._anchor_dir ()
856870 if run_dir .parent .name == "runs" :
857871 return run_dir .parents [1 ]
858872 return run_dir
859873
860874 def _report_dir (self ) -> Path :
861875 """Where a PDF is saved (Knut): an all-runs report belongs to the whole
862876 profile, so it goes in a ``reports`` folder next to ``runs/``; a single-run
863- report goes in that run's own ``reports`` folder."""
877+ report goes in that run's own ``reports`` folder. For an imported
878+ measurement it goes in a ``reports`` folder next to the file itself."""
864879 from core .file_manager import reports_subdir
865- run_dir = self ._ti3 . parent
880+ run_dir = self ._anchor_dir ()
866881 if self ._all_runs_check .isChecked () and run_dir .parent .name == "runs" :
867882 return reports_subdir (self ._profile_root ())
868883 return reports_subdir (run_dir )
@@ -872,7 +887,7 @@ def _on_reveal(self) -> None:
872887 the reports folder and open saved PDFs (Knut)."""
873888 from PyQt6 .QtCore import QUrl
874889 from PyQt6 .QtGui import QDesktopServices
875- if self ._ti3 :
890+ if self ._sources or self . _ti3 :
876891 QDesktopServices .openUrl (QUrl .fromLocalFile (str (self ._profile_root ())))
877892
878893 def _export_pdf (self ) -> None :
@@ -1045,12 +1060,18 @@ def _scope_header_units(self, runs: list) -> list:
10451060 from workflow .measurement_report import report_scope
10461061 sc = report_scope (runs )
10471062 names = list (dict .fromkeys (p ["name" ] for p in sc ["profiles" ])) # de-dup, ordered
1048- units = [n + ("," if i < len (names ) - 1 else "" )
1049- for i , n in enumerate (names )]
10501063 d0 , d1 = sc ["date_range" ]
10511064 n = sc ["total" ]
1052- units .append (" " + tr ("{n} measurement run" ).format (n = n ) if n == 1
1053- else " " + tr ("{n} measurement runs" ).format (n = n ))
1065+ # Listing every name gets unwieldy once there are many (e.g. a folder of
1066+ # imported measurements); past a handful, drop the names and let the run
1067+ # count + date range speak for the scope (Knut).
1068+ if len (names ) <= 4 :
1069+ units = [nm + ("," if i < len (names ) - 1 else "" )
1070+ for i , nm in enumerate (names )]
1071+ units .append (" " + (tr ("{n} measurement run" ).format (n = n ) if n == 1
1072+ else tr ("{n} measurement runs" ).format (n = n )))
1073+ else :
1074+ units = [tr ("{n} measurement runs" ).format (n = n )]
10541075 units [- 1 ] += f" ({ d0 } – { d1 } )"
10551076 # Trailing space on the name units so they don't run together.
10561077 return [(u + " " ) if u .endswith ("," ) else u for u in units ]
0 commit comments