Files
igor-public/pearl/pearl-scilog.ipf

1740 lines
51 KiB
Igor

#pragma TextEncoding = "UTF-8"
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma version = 2.2
#pragma IgorVersion = 8.0
#pragma ModuleName = PearlSciLog
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2025 Paul Scherrer Institut
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
/// @file
/// @brief Interface for writing SciLog entries with Igor graphs as attachment.
/// @ingroup ArpesPackage
///
///
/// The functions in this module support the following SciLog features:
/// - Submit new entries.
/// - Add text message.
/// - Add tags. Drop-down lists with common tags are provided.
/// - Attach Igor graphs.
/// - Not specific to the configuration at PEARL.
/// PEARL code is concentrated in the scilog_init_pearl_templates() function.
/// - The configuration of the server and logbooks
/// as well as the most recently used attributes are persisted in the preference file.
///
/// Setup:
/// 1. If there is no data folder `root:packages:pearl_scilog` yet:
/// Call `PearlScilog#init_package()`.
/// 2. The administrator of the SciLog server creates logbook templates
/// according to the configuration of the logbooks.
/// The templates are written in Igor code.
/// For PEARL, this is done in the scilog_init_pearl_templates() function.
/// 3. Install uv (https://docs.astral.sh/uv/getting-started/installation/).
/// Alternatively: Setup an environment containing Python and the pillow and scilog packages from PyPI.
/// 4. Adjust the root:packages:pearl_scilog:persistent:python_activate and python_command global strings.
/// By default, they are set for uv. In this case you can skip this step.
///
/// The first string must contain the command to activate the environment in a batch file,
/// for example: `call c:\programdata\miniforge3\scripts\activate.bat scilog`.
/// The second must be an executable that can be followed by a python script and arguments,
/// for example: `python.exe` or `uv run --script`.
/// 5. Save the user name and password in a credentials file.
///
/// Usage:
/// 1. The user opens logbooks via the _Open SciLog panel_ menu item or calling pearl_scilog().
/// Before first use, select a template and enter a name for the logbook.
/// The new logbook is written to the preference file,
/// and can afterwards be opened directly.
/// The name of the logbook is not connected to the name in SciLog.
/// 2. Enter the name of the SciLog logbook in the logbook edit field.
/// 3. Enter the p-group of the SciLog logbook in the pgroup edit field.
/// 4. Edit the message, choose tags and attachments as necessary, and submit to SciLog.
/// Each of the fields on the left, adds a tag.
/// Be sure to use memorable tags (for searching the logbook) and avoid spaces and commas.
///
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2025 Paul Scherrer Institut @n
/// Licensed under the Apache License, Version 2.0 (the "License"); @n
/// you may not use this file except in compliance with the License. @n
/// You may obtain a copy of the License at
/// http://www.apache.org/licenses/LICENSE-2.0
/// @namespace PearlSciLog
/// @brief interface for writing SciLog entries with Igor graphs as attachment.
///
/// PearlSciLog is declared in @ref pearl-scilog.ipf.
static strconstant package_name = "pearl_scilog"
static strconstant package_path = "root:packages:pearl_scilog:"
static constant kdfRoot = 0
static constant kdfVolatile = 1
static constant kdfPersistent = 2
static constant kdfTemplates = 3
/// main function to initialize and open a SciLog panel.
///
/// this function takes care of all necessary initialization, configuration, and preferences.
/// if a panel exists, it will be moved to the front.
///
/// @param logbook name of the logbook
/// if empty, the user is prompted to select or create a logbook by scilog_prompt_logbook().
///
///
function pearl_scilog(logbook)
string logbook
if (init_package() == 0)
load_prefs()
string templates = list_logbooks(templates=1)
if (ItemsInList(templates) < 1)
scilog_init_pearl_templates()
endif
endif
if (strlen(logbook) > 0)
dfref df = get_scilog_df(logbook, kdfPersistent)
if (DataFolderRefStatus(df) != 1)
print "Configuration of logbook", logbook, "not found. Please create a new one."
logbook = ""
endif
endif
if (strlen(logbook) == 0)
logbook = scilog_prompt_logbook()
endif
string win_name = CleanupName(logbook, 0) + "SciLogPanel"
if (strlen(logbook) > 0)
string wins = WinList(win_name + "*", ";", "WIN:64")
if (strlen(wins) > 0)
win_name = StringFromList(0, wins, ";")
DoWindow /F $win_name
else
win_name = PearlSciLogPanel(logbook, win_name)
STRUCT WMWinHookStruct s
s.eventCode = 0
s.winName = win_name
scilog_panel_hook(s)
endif
endif
end
/// save preferences and recent values before Igor opens a new experiment.
static function IgorBeforeNewHook(igorApplicationNameStr)
string igorApplicationNameStr
save_prefs()
cleanup_temp_files()
return 0
end
/// save preferences and recent values before Igor quits.
static function IgorQuitHook(igorApplicationNameStr)
string igorApplicationNameStr
save_prefs()
cleanup_temp_files()
return 0
end
/// initialize the package and reload preferences after an experiment is loaded.
static function AfterFileOpenHook(refNum,file,pathName,type,creator,kind)
Variable refNum,kind
String file,pathName,type,creator
if( (kind >= 1) && (kind <= 2))
clear_package_data()
endif
return 0
end
/// get the package, logbook, or template datafolder.
///
/// @param name name of logbook or template, or empty string for respective parent folder.
///
/// @param category parameter category:
/// @arg kdfRoot package root
/// @arg kdfVolatile volatile
/// @arg kdfPersistent persistent
/// @arg kdfTemplates template
///
/// @returns data folder reference
///
static function /df get_scilog_df(name, category)
string name
variable category
dfref df_package = $package_path
dfref df_persistent = df_package:persistent
dfref df_volatile = df_package:volatile
switch(category)
case kdfRoot:
dfref df_parent = df_package
break
case kdfPersistent:
dfref df_parent = df_persistent
break
case kdfTemplates:
dfref df_parent = df_persistent:templates
break
case kdfVolatile:
dfref df_parent = df_volatile
break
default:
Abort "get_scilog_df: undefined data folder category."
endswitch
if ((strlen(name) > 0) && (category >= 1))
if (category == kdfTemplates)
dfref df_logbooks = df_parent
else
dfref df_logbooks = df_parent:logbooks
endif
dfref df_logbook = df_logbooks:$name
return df_logbook
else
return df_parent
endif
end
/// delete all package data
///
/// also kills any SciLog panels
///
static function clear_package_data()
dfref savedf = getdatafolderdfr()
dfref df_root = get_scilog_df("", kdfRoot)
if (DataFolderRefStatus(df_root) == 1)
string wins = WinList("*SciLogPanel*", ";", "WIN:64")
variable iwin
variable nwin = ItemsInList(wins, ";")
string swin
for (iwin = 0; iwin < nwin; iwin += 1)
swin = StringFromList(iwin, wins, ";")
KillWindow /Z $swin
endfor
KillDataFolder /Z df_root
endif
setdatafolder savedf
return 0
end
/// initialize the package data folder.
///
/// the data folder is initialized with a default, local configuration without any logbooks.
/// the server configuration should be set in the preferences.
///
/// @param clean decides what to do if the package configuration exists.
/// @arg 0 (default) keep existing configuration.
/// @arg 1 overwrite existing configuration.
///
static function init_package([clean])
variable clean
if (ParamIsDefault(clean))
clean = 0
endif
dfref savedf = getdatafolderdfr()
dfref df_root = get_scilog_df("", kdfRoot)
if ((clean == 0) && (DataFolderRefStatus(df_root) == 1))
return 1
endif
setdatafolder root:
newdatafolder /o/s packages
newdatafolder /o/s $package_name
dfref df_package_root = getdatafolderdfr()
newdatafolder /o/s volatile
dfref df_volatile = getdatafolderdfr()
newdatafolder /o logbooks
setdatafolder df_package_root
newdatafolder /o/s persistent
dfref df_persistent = getdatafolderdfr()
newdatafolder /o logbooks
newdatafolder /o templates
// common configuration
setdatafolder df_persistent
// batch commands to activate the python environment and to run python.
// adjust the global strings manually after initialization!
string /g python_activate = "echo calling uv"
string /g python_command = "uv run --script"
variable /g loglevel = 4
setdatafolder savedf
return 0
end
/// setup PEARL template logbooks.
///
/// template logbooks for PEARL.
///
/// @remark this function is specific to the setup at PEARL.
///
function scilog_init_pearl_templates()
dfref savedf = getdatafolderdfr()
dfref df_root = get_scilog_df("", kdfRoot)
dfref df_persistent = get_scilog_df("", kdfPersistent)
dfref df_templates = get_scilog_df("", kdfTemplates)
// Experiments template
setdatafolder df_templates
newdatafolder /o/s Experiments
// attributes (persistent)
// available attributes
string /g attributes = "author;pgroup;logbook;project;sample;file;system;source;task;method;technical;program;revision;machine;job;tags;valid;"
// controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
string /g controls = "author:sv_author;pgroup:sv_pgroup;logbook:sv_logbook;project:sv_project;sample:sv_sample;file:sv_file;system:pm_system;source:pm_source;task:pm_task;method:pm_method;technical:pm_technical;program:sv_program;revision:sv_revision;machine:sv_machine;job:sv_job;tags:sv_tags;valid:cb_valid;"
// attributes with fixed options, value item declares the options string
string /g options = "source=sources;task=tasks;method=methods;technical=technicals;system=systems;"
// attributes which must be defined
string /g required_attributes = "author;pgroup;logbook;"
// help strings
string /g helps = "author:e-mail address of author (required);"
helps += "pgroup:p-group (required);"
helps += "logbook:title of existing scilog logbook (required);"
helps += "project:proposal number or (short) project name (optional), avoid spaces and commas;"
helps += "sample:short sample name (optional), avoid spaces and commas;"
helps += "file:name of original data file (optional), avoid spaces and commas, do not include path;"
helps += "system:instrument part, choose Other to suppress the tag;"
helps += "source:data source, choose Other to suppress the tag;"
helps += "task:purpose of the measurement, choose Other to suppress the tag;"
helps += "method:measurement method or technique, choose Other to suppress the tag;"
helps += "technical:technical procedure, choose Other to suppress the tag;"
helps += "tags:other comma-separated tags (optional), avoid spaces;"
helps += "program:program code for calculations (optional), avoid spaces and commas;"
helps += "revision:code revision for calculations, e.g. git hash or tag (optional), avoid spaces and commas;"
helps += "machine:computing host name for calculations (optional), avoid spaces and commas;"
helps += "job:calculation job name (optional), avoid spaces and commas;"
helps += "valid:uncheck if data is unusable, incomplete or obviously wrong;"
// option lists
string /g sources = "PShell;Scienta;SScan;Prosilica;OTF;EPICS;LEED;QMS;Matrix;Nanonis;Igor Pro;Other"
string /g tasks = "Measurement;Optimization;Analysis;Sample Preparation;Sample Storage;Comment;Development;Maintenance;Test;Other"
string /g methods = "XPS;XPD;UPS;XAS;XMCD;PED;ARPES;STM;STS;LEED;AES;QMS;MBE;Sputter/Anneal;Test;Other"
string /g technicals = "Installation;Repair;Maintenance;Test;Commissioning;Bakeout;Incident;Cool-down;Warm-up;Storage;Other"
string /g systems = "Vacuum;Control System;BL;XA;XP;SA;SP;T;LL;Monochromator;Carving;Scienta;STM;PC-Scienta;PC-Matrix;PC-Console;PC-Console-Win;PC-XP;EPS;LAC;Desiccator;Other"
setdatafolder savedf
return 0
end
/// initialize volatile variables.
///
/// create and initialize all volatile variables for the configured notebooks.
/// values of existing variables are not changed.
///
/// this function must be called after new logbooks have been configured,
/// specifically by scilog_create_logbook() and load_prefs().
///
static function init_volatile_vars()
dfref savedf = GetDataFolderDFR()
dfref df_volatile_root = get_scilog_df("", kdfVolatile)
dfref df_volatile_parent = df_volatile_root:logbooks
string logbooks = list_logbooks()
string logbook
variable nlb = ItemsInList(logbooks)
variable ilb
SetDataFolder df_volatile_root
if (exists("temp_graph_files") != 2)
string /g temp_graph_files = ""
endif
for (ilb = 0; ilb < nlb; ilb += 1)
logbook = StringFromList(ilb, logbooks)
SetDataFolder df_volatile_parent
if (DataFolderExists(logbook))
SetDataFolder $logbook
else
NewDataFolder /o/s $logbook
endif
if (exists("att_list") != 1)
make /n=(0,3) /t /o attach_list
make /n=(0,3) /i /o attach_sel
endif
if (exists("url") != 2)
string /g url = ""
endif
endfor
SetDataFolder savedf
return 0
end
/// @var persistent:loglevel
/// @brief filter history messages by log level.
///
/// messages are printed to the history only if their level exceeds this setting.
/// this is a global variable in the "persistent" folder of the package configuration.
///
/// @arg 0 none. do not print any messages. no messages have this level.
/// @arg 1 critical. severe error with possible data corruption.
/// @arg 2 error. a function did not complete successfully.
/// @arg 3 warning. everything worked fine, but some attention of the user is required.
/// @arg 4 info. status message which may be useful to the normal user.
/// @arg 5 debug. status message which may be useful to the developer.
///
/// create a new logbook.
///
/// create a new empty logbook or duplicate from a template.
///
/// @param name name of the new logbook.
/// if the logbook exists, the existing logbook folder is killed
/// and replaced by a new one.
/// this may fail if a window is still open.
///
/// @param template name of the template.
/// if empty string, a new empty logbook is created.
///
function scilog_create_logbook(name, [script_path, template])
string name
string script_path
string template
if (ParamIsDefault(script_path))
script_path = ""
endif
if (ParamIsDefault(template))
template = ""
endif
dfref savedf = getdatafolderdfr()
dfref df_root = get_scilog_df("", kdfRoot)
dfref df_persistent_root = get_scilog_df("", kdfPersistent)
dfref df_persistent_parent = df_persistent_root:logbooks
dfref df_volatile_root = get_scilog_df("", kdfVolatile)
dfref df_volatile_parent = df_volatile_root:logbooks
setdatafolder df_persistent_parent
if (CheckName(name, 11) != 0)
setdatafolder savedf
Abort "invalid logbook name"
return -1
endif
if (strlen(template) > 0)
dfref df_template = get_scilog_df(template, kdfTemplates)
dfref df_existing = get_scilog_df(name, kdfPersistent)
if (DataFolderRefStatus(df_existing))
KillDataFolder /Z df_existing
endif
DuplicateDataFolder df_template, df_persistent_parent:$name
else
NewDataFolder /o/s df_persistent_parent:$name
// SciLog logbook name
string /g logbook = name
// SciLog script path
string /g scilog_path = script_path
// attributes (persistent)
// available attributes
string /g attributes = ""
// controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
string /g controls = ""
// attributes with fixed options, value item declares the options string
string /g options = ""
// attributes which must be defined
string /g required_attributes = ""
endif
// usage data (persistent)
setdatafolder get_scilog_df(name, kdfPersistent)
string /g recent = ""
string /g recent_message = ""
init_volatile_vars()
setdatafolder savedf
return 0
end
/// save persistent package data to the preferences file.
///
/// saves everything under the persistent folder of the package.
///
static function save_prefs()
dfref saveDF = GetDataFolderDFR()
dfref df = get_scilog_df("", kdfPersistent)
if (DataFolderRefStatus(df) == 1)
string fullPath = SpecialDirPath("Packages", 0, 0, 0)
fullPath += package_name
NewPath/O/C/Q tempPackagePrefsPath, fullPath
fullPath += ":preferences.pxp"
SetDataFolder df
SaveData /O /Q /R fullPath
KillPath/Z tempPackagePrefsPath
endif
SetDataFolder saveDF
end
/// load persistent package data from the preferences file.
///
/// the preferences file is an Igor packed experiment file in a special preferences folder
static function load_prefs()
dfref saveDF = GetDataFolderDFR()
variable result = -1
init_package()
setdatafolder get_scilog_df("", kdfPersistent)
string fullPath = SpecialDirPath("Packages", 0, 0, 0)
fullPath += package_name
GetFileFolderInfo /Q /Z fullPath
if (V_Flag == 0) // Disk directory exists?
fullPath += ":preferences.pxp"
GetFileFolderInfo /Q /Z fullPath
if (V_Flag == 0) // Preference file exist?
LoadData /O /R /Q fullPath
init_volatile_vars()
result = 0
endif
endif
SetDataFolder saveDF
return result
end
/// get a list of configured logbooks or templates.
///
/// this is list of data folder names under persistent:logbooks (or persistent:templates).
/// the function does not check whether the folders contain valid data.
///
/// @param templates select whether logbooks (0, default) or templates (1) are returned.
///
/// @return semicolon-separated list of logbooks
///
static function /s list_logbooks([templates])
variable templates
if (ParamIsDefault(templates))
templates = 0
endif
dfref df_persistent = get_scilog_df("", kdfPersistent)
if (templates)
dfref df_logbooks = df_persistent:templates
else
dfref df_logbooks = df_persistent:logbooks
endif
string logbooks = ""
variable nlb = CountObjectsDFR(df_logbooks, 4)
variable ilb
string slb
for (ilb = 0; ilb < nlb; ilb += 1)
slb = GetIndexedObjNameDFR(df_logbooks, 4, ilb)
if (strlen(slb) > 0)
logbooks = AddListItem(slb, logbooks)
endif
endfor
return SortList(logbooks, ";", 16)
end
/// validate attributes
///
/// @returns 0 if all required attributes are present and enumerated items are correct.
/// non-zero if a violation is detected.
/// -1: invalid author
/// -2: invalid p-group
/// -3: empty message
/// -4: missing required attribute
///
function scilog_validate_attributes(logbook, attributes, message)
string logbook // name of the logbook (as in igor folder name)
string attributes // key=value list of attributes, semicolon separated
string message
dfref df_logbook = get_scilog_df(logbook, kdfPersistent)
svar /sdfr=df_logbook required_attributes
variable result = 0
variable ii
variable nn = ItemsInList(required_attributes, ";")
string att, val
for (ii=0; ii < nn; ii+=1)
att = StringFromList(ii, required_attributes, ";")
val = StringByKey(att, attributes, ":", ";")
if (strlen(val) == 0)
print "SciLog: Missing required attribute", att
result = -4
endif
endfor
if (strlen(message) == 0)
print "SciLog: Empty message"
result = -3
endif
if (!GrepString(StringByKey("pgroup", attributes, ":", ";"), "p[1-9][0-9]{4}"))
print "SciLog: Invalid p-group"
result = -2
endif
if (StringMatch(StringByKey("author", attributes, ":", ";"), "!*@*.*"))
print "SciLog: Author must be an e-mail address"
result = -1
endif
return result
end
/// create a new entry in SciLog
///
/// this is the main function to create a new entry in a logbook.
///
/// @param logbook name of the target logbook.
///
/// @param attributes attributes list from get_panel_attributes.
///
/// @param message plain text part of the entry.
///
/// @param graphs names of graph windows to be added as attachments, semicolon separated.
///
/// @return ID number of the new entry (> 0), or error code (< 0).
/// @arg -1: failed to save temporary message file.
/// @arg -2: invalid/missing command line.
/// @arg -3: invalid/missing attributes.
/// @arg -4: scilog returned error
///
function scilog_create_entry(logbook, attributes, message, [graphs])
string logbook
string attributes
string message
string graphs
if (ParamIsDefault(graphs))
graphs = ""
endif
dfref savedf = getdatafolderdfr()
dfref df_general = get_scilog_df("", kdfPersistent)
dfref df_volatile = get_scilog_df(logbook, kdfVolatile)
variable result = 0
nvar /sdfr=df_general loglevel
if (strlen(message) == 0)
return -1
endif
if (strlen(attributes) == 0)
return -3
endif
message = scilog_format_message(logbook, attributes, message, graphs=graphs)
string graph_files = prepare_graph_attachments(graphs)
string attrs_file = create_attrs_file(logbook, attributes, graph_files)
string message_file = create_message_file(message)
string cmd_file_path = create_cmd_file(logbook, attrs_file, message_file)
string log_file_path = ReplaceString(".bat", cmd_file_path, ".log")
ExecuteScriptText cmd_file_path
string error = parse_result(log_file_path)
if (strlen(error) == 0)
print "Message sent successfully."
result = 0
else
print "Error sending message:"
print error
result = -4
endif
setdatafolder savedf
return result
end
/// format the message with special attributes
///
/// adds a first line with important attributes: file and sample if present.
///
/// @param logbook name of the target logbook.
///
/// @param attributes attributes list from get_panel_attributes.
///
/// @param message plain text part of the entry.
///
/// @param graphs names of graph windows to be added as attachments, semicolon separated.
///
/// @return formatted message
///
function /s scilog_format_message(logbook, attributes, message, [graphs])
string logbook
string attributes
string message
string graphs
if (ParamIsDefault(graphs))
graphs = ""
endif
string file = StringByKey("file", attributes, ":", ";")
string sample = StringByKey("sample", attributes, ":", ";")
string result = ""
string sep = ""
if (strlen(file) > 0)
result += "File: " + file + "\r\n"
sep = "\r\n"
endif
if (strlen(sample) > 0)
result += "Sample: " + sample + "\r\n"
sep = "\r\n"
endif
result += sep
result += message
setdatafolder savedf
return result
end
/// create a batch file for the ingestion command
///
/// the file contains commands to:
/// 1. activate the python environment (from the python_activate global string).
/// 2. call scilog-ingest.py with python.
///
/// the file is written to the user's temporary directory and can be executed by ExecuteScriptText.
/// stderr and stdout of the python shell are captured in the scilog.log file.
///
/// @param logbook name of the target logbook
///
static function /s create_cmd_file(logbook, attrs_file, message_file)
string logbook
string attrs_file
string message_file
dfref df_general = get_scilog_df("", kdfPersistent)
svar /sdfr=df_general python_activate
svar /sdfr=df_general python_command
string path = SpecialDirPath("Temporary", 0, 1, 0)
string log_file = path + "scilog.log"
String ipf_path_igor = ParseFilePath(1, FunctionPath(""), ":", 1, 0)
String ipf_path_win = ParseFilePath(5, ipf_path_igor, "\\", 0, 0)
String bat_text
bat_text = "cd \"" + ipf_path_win + "\"\r\n"
bat_text += python_activate + "\r\n"
bat_text += python_command + " scilog-ingest.py \"" + attrs_file + "\" \"" + message_file + "\""
bat_text += " > \"" + log_file + "\" 2>&1\r\n"
string filename
variable len = strlen(path)
if (numtype(len) == 0)
filename = "scilog.bat"
path += filename
variable f1
Open/z f1 as path
fprintf f1, bat_text
Close f1
else
filename = ""
endif
return path
end
/// prepare screenshots of graph windows for attachments
///
/// prepares the attachment files from Igor graph windows.
///
/// @param graphs names of graph windows to be added as attachments, semicolon separated
///
static function /s prepare_graph_attachments(graphs)
string graphs // names of graph windows to be added as attachments, semicolon separated
string cmd = ""
variable ngraphs = ItemsInList(graphs, ";")
variable igraph
string sgraph
string graph_path
for (igraph = 0; igraph < ngraphs; igraph += 1)
sgraph = StringFromList(igraph, graphs, ";")
graph_path = create_graph_file(sgraph, igraph)
if (strlen(graph_path) > 0)
cmd += graph_path + ";"
endif
endfor
return cmd
end
static function /s get_timestamp(sep)
string sep
Variable now = DateTime
string dat = ReplaceString("-", Secs2Date(DateTime, -2), "")
string tim = ReplaceString(":", Secs2Time(DateTime, 3), "")
return dat + sep + tim
end
/// save the message to a temporary text file
///
/// the file is saved to the Temporary directory returned by igor's SpecialDirPath function
/// under the file name "scilog_temp_message.txt".
/// the function returns the file path
///
/// @param message text message to save to the file.
/// @return (string) path of the created file.
/// empty string if unsuccessful.
///
///
static function /s create_message_file(message)
string message
string path = SpecialDirPath("Temporary", 0, 1, 0)
variable len = strlen(path)
string filename
if (numtype(len) == 0)
filename = "scilog_temp_message.txt"
path += filename
variable f1
Open f1 as path
fprintf f1, message
Close f1
else
filename = ""
endif
return path
end
/// save a graph to a temporary graphics file
///
/// the file is saved to the Temporary directory returned by igor's SpecialDirPath function.
/// the file name contains a time stamp and the specified file index to make it unique.
/// the function returns the name of the file (excluding path!)
///
/// the full path is added to the temp_graph_files global list.
/// a hook function will delete the files listed there when igor quits.
///
/// @param graphname object name of the graph to save.
/// @param fileindex incrememtal index of the file within one submission.
/// the file name is made unique by a time stamp and this file index.
/// submissions within the same second must have a unique file index.
/// @return (string) path of the created file.
/// empty string if unsuccessful.
///
static function /s create_graph_file(graphname, fileindex)
string graphname
variable fileindex
dfref df_volatile_root = get_scilog_df("", kdfVolatile)
svar /sdfr=df_volatile_root temp_graph_files
string path = SpecialDirPath("Temporary", 0, 1, 0)
string ts = get_timestamp("_")
variable len = strlen(path)
string filename
if (numtype(len) == 0)
filename = "scilog_" + ts + "_" + num2str(fileindex) + ".png"
path += filename
SavePICT /B=72 /E=-5 /M /O /W=(0,0,8,6) /WIN=$graphname /Z as path
if (v_flag == 0)
temp_graph_files = AddListItem(path, temp_graph_files, ";", inf)
else
filename = ""
endif
else
filename = ""
endif
return path
end
/// write the attributes to a file.
///
///
/// @param attributes attributes list from get_panel_attributes.
static function /s create_attrs_file(logbook, attributes, attachments)
string logbook
string attributes
string attachments
dfref df_general = get_scilog_df("", kdfPersistent)
nvar /sdfr=df_general loglevel
variable i_, n_, j_, m_
string s_
string k_, v_
string work_path = SpecialDirPath("Temporary", 0, 1, 0)
variable len = strlen(work_path)
if (numtype(len) == 0)
string cmdx = ""
string cmd_path = work_path + "scilog_temp_attr.dat"
variable f1
Open f1 as cmd_path
n_ = ItemsInList(attributes, ";")
for (i_=0; i_<n_; i_+=1)
s_ = StringFromList(i_, attributes, ";")
k_ = StringFromList(0, s_, ":")
v_ = StringFromList(1, s_, ":")
if (cmpstr(k_, "author") == 0)
cmdx = "author:" + v_ + "\r\n"
elseif (cmpstr(k_, "pgroup") == 0)
cmdx = "pgroup:" + v_ + "\r\n"
elseif (cmpstr(k_, "logbook") == 0)
cmdx = "logbook:" + v_ + "\r\n"
elseif (cmpstr(k_, "location") == 0)
cmdx = "location:" + v_ + "\r\n"
elseif (cmpstr(k_, "valid") == 0)
if (cmpstr(v_, "0") == 0)
cmdx = "tag:invalid\r\n"
endif
elseif (cmpstr(k_, "tags") == 0)
m_ = ItemsInList(v_, ",")
cmdx = ""
for (j_=0; j_<m_; j_+=1)
s_ = StringFromList(j_, v_, ",")
cmdx += "tag:" + s_ + "\r\n"
endfor
elseif ((strlen(v_) > 0) && (cmpstr(v_, "Other") != 0))
cmdx = "tag:" + v_ + "\r\n"
else
cmdx = ""
endif
if (strlen(v_) && strlen(cmdx))
fprintf f1, cmdx
endif
endfor
n_ = ItemsInList(attachments, ";")
for (i_=0; i_<n_; i_+=1)
s_ = StringFromList(i_, attachments, ";")
cmdx = "attachment:" + s_ + "\r\n"
fprintf f1, cmdx
endfor
Close f1
else
cmd_path = ""
endif
return cmd_path
end
static function /s get_log_path()
string path = SpecialDirPath("Temporary", 0, 1, 0)
variable len = strlen(path)
if (numtype(len) == 0)
path += "scilog.log"
else
path = ""
endif
return path
end
/// delete temporary files created by the SciLog module.
///
/// this deletes all temporary graph files that are referenced by the volatile temp_graph_files list.
/// temp_graph_files is a semicolon-delimited string.
/// items are added by create_graph_file().
///
/// this function should be called before a new experiment is loaded or igor quits.
///
static function cleanup_temp_files()
dfref df_volatile_root = get_scilog_df("", kdfVolatile)
if (DataFolderRefStatus(df_volatile_root))
svar /sdfr=df_volatile_root /z temp_graph_files
if (SVAR_Exists(temp_graph_files))
variable nfi = ItemsInList(temp_graph_files)
variable ifi
string sfi
for (ifi = 0; ifi < nfi; ifi += 1)
sfi = StringFromList(ifi, temp_graph_files)
DeleteFile /Z sfi
endfor
temp_graph_files = ""
endif
endif
return 0
end
static strconstant scilog_success_match = "*Success*"
static strconstant scilog_error_match = "*Error*"
static strconstant scilog_exception_match = "*Exception*"
/// parse the result file from an scilog invokation.
///
/// @param path path to scilog-ingest log file
///
/// @returns empty string if successful, abbreviated error message otherwise
///
static function /s parse_result(path)
string path
dfref df_general = get_scilog_df("", kdfPersistent)
nvar /sdfr=df_general loglevel
string line = ""
string output = ""
string error = ""
variable success = 0
string part1 = ""
string part2 = ""
variable len = strlen(path)
if (numtype(len) == 0)
variable f1
Open /R/Z f1 as path
if (v_flag == 0)
do
FReadLine f1, line
if (strlen(line) == 0)
break
else
output += line
endif
if (StringMatch(line, scilog_error_match))
error += line
elseif (StringMatch(line, scilog_exception_match))
error += line
elseif (StringMatch(line, scilog_success_match))
success = 1
endif
while(!success)
Close f1
endif
endif
if (loglevel >= 5)
print output
endif
if (success)
return ""
elseif (strlen(error) == 0)
return output
else
return error
endif
end
/// prompt to open or create a logbook
///
function /s scilog_prompt_logbook()
string logbooks = list_logbooks(templates=0)
logbooks = AddListItem("(new)", logbooks)
string templates = list_logbooks(templates=1)
templates = AddListItem("(none)", templates)
string logbook = StringFromList(0, logbooks)
string template = StringFromList(0, logbooks)
string name = ""
prompt logbook, "logbook", popup logbooks
prompt template, "template", popup templates
prompt name, "new logbook name"
doprompt "select logbook", logbook, template, name
if (!v_flag)
if (cmpstr(logbook, "(new)") == 0)
scilog_create_logbook(name, template=template)
logbook = name
endif
else
logbook = ""
endif
return logbook
end
/// open a new panel for submitting data to SciLog.
///
/// this function creates only the panel but not the necessary data folders.
/// call init_package() and load_prefs() once before creating panels.
///
/// @param logbook name of the target logbook
/// @param win_name desired window name. igor may modify it to make it unique.
/// @return actual window name
///
function /s PearlSciLogPanel(logbook, win_name)
string logbook
string win_name
dfref savedf = getdatafolderdfr()
dfref df_general = get_scilog_df("", kdfPersistent)
dfref df_persistent = get_scilog_df(logbook, kdfPersistent)
dfref df_volatile = get_scilog_df(logbook, kdfVolatile)
string win_title = "SciLog " + logbook
NewPanel /K=1 /N=$win_name /W=(600,200,1200,700) as win_title
win_name = s_name
ModifyPanel /w=$win_name cbRGB=(52224,52224,65280)
svar /sdfr=df_persistent attributes
svar /sdfr=df_persistent controls
svar /sdfr=df_persistent options
svar /sdfr=df_persistent helps
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
svar /sdfr=df_volatile url
variable iattr
variable nattr = ItemsInList(attributes, ";")
string s_attr
string s_control
string s_option
string s_help
string persistent_path = GetDataFolder(1, df_persistent)
string volatile_path = GetDataFolder(1, df_volatile)
string options_path
string variable_path
variable ypos = 2
variable height = 0
for (iattr = 0; iattr < nattr; iattr += 1)
s_attr = StringFromList(iattr, attributes, ";")
s_control = StringByKey(s_attr, controls, ":", ";")
s_help = StringByKey(s_attr, helps, ":", ";")
strswitch(s_control[0,1])
case "sv":
SetVariable $s_control, win=$win_name, pos={0,ypos}, size={300,16}, bodyWidth=230
SetVariable $s_control, win=$win_name, title=s_attr, value= _STR:""
SetVariable $s_control, win=$win_name, userdata(attribute)=s_attr
if (strlen(s_help))
SetVariable $s_control, win=$win_name, help={s_help}
endif
ypos += 18
break
case "pm":
options_path = persistent_path + StringByKey(s_attr, options, "=", ";")
PopupMenu $s_control, win=$win_name, pos={0,ypos}, size={300,21}, bodyWidth=230
PopupMenu $s_control, win=$win_name, title=s_attr
PopupMenu $s_control, win=$win_name, mode=1, popvalue="Other", value= #options_path
PopupMenu $s_control, win=$win_name, userdata(attribute)=s_attr
if (strlen(s_help))
PopupMenu $s_control, win=$win_name, help={s_help}
endif
ypos += 23
break
case "cb":
CheckBox $s_control, win=$win_name, pos={70,ypos}, size={300,14}
CheckBox $s_control, win=$win_name, title=s_attr, value= 1
CheckBox $s_control, win=$win_name, userdata(attribute)=s_attr
if (strlen(s_help))
CheckBox $s_control, win=$win_name, help={s_help}
endif
ypos += 17
break
endswitch
endfor
ypos = max(ypos, 80)
TitleBox t_attach, win=$win_name, pos={308,5}, size={70,14}, title="Attachments", frame=0
TitleBox t_attach, help={"Plain text message. Each line is converted into a paragraph in HTML. To use HTML formatting, start with tag."}
height = ypos - 21 - 4
ListBox lb_attach, win=$win_name, pos={308,21}, size={264,height}
ListBox lb_attach, win=$win_name, listWave=attach_list
ListBox lb_attach, win=$win_name, mode=1, selWave=attach_sel, selRow=-1
ListBox lb_attach, win=$win_name, widths={20,160,80}
ListBox lb_attach, win=$win_name, help={"Choose graphs to attach to the message."}
Button b_attach_top, win=$win_name, pos={420,2}, size={40,18}, title="top"
Button b_attach_top, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_top, win=$win_name, proc=PearlSciLog#bp_attach_top
Button b_attach_top, win=$win_name, help={"Select top graph for attachment."}
Button b_attach_all, win=$win_name, pos={460,2}, size={40,18}, title="all"
Button b_attach_all, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_all, win=$win_name, proc=PearlSciLog#bp_attach_allnone
Button b_attach_all, win=$win_name, help={"Select all graphs for attachment."}
Button b_attach_none, win=$win_name, pos={500,2}, size={40,18}, title="none"
Button b_attach_none, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_none, win=$win_name, proc=PearlSciLog#bp_attach_allnone
Button b_attach_none, win=$win_name, help={"Deselect all attachments."}
Button b_save_graphs, win=$win_name, pos={540,2}, size={40,18}, title="save"
Button b_save_graphs, win=$win_name, fcolor=(56576,60928,47872)
Button b_save_graphs, win=$win_name, proc=PearlSciLog#bp_save_graphs
Button b_save_graphs, win=$win_name, help={"Save selected graphs as PNG bitmap files."}
Button b_attach_up, win=$win_name, pos={576,20}, size={20,20}, title="\\W517"
Button b_attach_up, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_up, win=$win_name, proc=PearlSciLog#bp_attach_updown
Button b_attach_up, win=$win_name, help={"Move selected graph up."}
Button b_attach_dw, win=$win_name, pos={576,40}, size={20,20}, title="\\W523"
Button b_attach_dw, win=$win_name, fcolor=(56576,60928,47872)
Button b_attach_dw, win=$win_name, proc=PearlSciLog#bp_attach_updown
Button b_attach_dw, win=$win_name, help={"Move selected graph down."}
ypos += 246-160
Button b_submit,win=$win_name, pos={70,ypos},size={46,20},proc=PearlSciLog#bp_submit,title="Submit"
Button b_submit,win=$win_name, help={"Submit form data to SciLog (new entry)."}
Button b_submit,win=$win_name, fcolor=(56576,60928,47872)
Button b_clear,win=$win_name, pos={120,ypos},size={46,20},proc=PearlSciLog#bp_clear,title="Clear"
Button b_clear,win=$win_name, help={"Clear the form fields"}
Button b_clear,win=$win_name, fcolor=(56576,60928,47872)
ypos += 272-246
ypos += 270-272
SetWindow $win_name, hook(scilogPanelHook)=PearlSciLog#scilog_panel_hook
SetWindow $win_name, userdata(logbook)=logbook
ypos += 160-270
TitleBox t_message,win=$win_name, pos={10,ypos},size={58,16},fixedSize=1,frame=0,anchor=RT,title="Message"
DefineGuide UGH0={FT,ypos},UGV0={FL,70},UGH1={FB,-52},UGV1={FR,-2}
NewNotebook /F=0 /N=Message /OPTS=3 /W=(115,404,345,341)/FG=(UGV0,UGH0,UGV1,UGH1) /HOST=#
Notebook kwTopWin, defaultTab=20, statusWidth=0, autoSave=0
Notebook kwTopWin fSize=10, fStyle=0, textRGB=(0,0,0)
RenameWindow #,Message
string nb_name = win_name + "#Message"
SetActiveSubwindow ##
// restore recently used attributes and message
svar /z /sdfr=df_persistent recent
if (svar_exists(recent) && (strlen(recent) > 0))
set_panel_attributes(win_name, recent)
endif
svar /z /sdfr=df_persistent recent_message
if (svar_exists(recent_message) && (strlen(recent_message) > 0))
set_panel_message(win_name, recent_message)
endif
Notebook $nb_name selection={startOfFile,startOfFile}, findText={"",1}
setdatafolder savedf
return win_name
end
static function scilog_panel_hook(s)
STRUCT WMWinHookStruct &s
Variable hookResult = 0
switch(s.eventCode)
case 0: // activate
string logbook = GetUserData(s.winName, "", "logbook")
if (strlen(logbook) > 0)
dfref df_volatile = get_scilog_df(logbook, kdfVolatile)
update_attach_items(logbook)
endif
break
case 6: // resize
// move bottom-aligned controls when the window is resized
variable b_top = s.winRect.bottom - 20
Button b_submit,pos={70,b_top}
Button b_clear,pos={120,b_top}
break
endswitch
return hookResult // 0 if nothing done, else 1
end
static constant kAttachColSel = 0
static constant kAttachColTitle = 1
static constant kAttachColName = 2
/// update the list of attachments
static function update_attach_items(logbook)
string logbook
dfref savedf = getdatafolderdfr()
dfref df_volatile = get_scilog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
if (!waveexists(attach_list))
return -1
endif
string names = WinList("*", ";", "WIN:1;VISIBLE:1")
names = SortList(names, ";", 16)
// remove closed graphs
variable i
variable k
variable n = DimSize(attach_list, 0)
string s
for (i = n-1; i >= 0; i -= 1)
s = attach_list[i][kAttachColName]
if (WhichListItem(s, names) < 0)
DeletePoints /M=0 i, 1, attach_list, attach_sel
endif
endfor
// add new graphs
n = ItemsInList(names)
for (i = 0; i < n; i += 1)
s = StringFromList(i, names)
FindValue /text=s /txop=4 /z attach_list
if (v_value < 0)
k = DimSize(attach_list, 0)
Redimension /n=(k+1,3) attach_list, attach_sel
//InsertPoints /M=0 k, 1, attach_list, attach_sel
attach_list[k][kAttachColSel] = ""
attach_list[k][kAttachColTitle] = ""
attach_list[k][kAttachColName] = s
attach_sel[k][kAttachColSel] = 32
attach_sel[k][kAttachColTitle] = 0
attach_sel[k][kAttachColName] = 0
endif
endfor
// update titles
n = DimSize(attach_list, 0)
for (i = n-1; i >= 0; i -= 1)
s = attach_list[i][kAttachColName]
getwindow /z $s, wtitle
if (v_flag == 0)
attach_list[i][kAttachColTitle] = s_value
else
attach_list[i][kAttachColTitle] = s
endif
endfor
setdatafolder savedf
return 0
end
/// move an attachment item in the list of attachments
static function move_attach_item(logbook, item, distance)
string logbook
variable item
variable distance
dfref savedf = getdatafolderdfr()
dfref df_volatile = get_scilog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
variable n = DimSize(attach_list, 0)
variable dest = item + distance
if ((item >= 0) && (item < n) && (dest >= 0) && (dest < n))
string name = attach_list[item][kAttachColName]
variable sel = attach_sel[item][kAttachColSel]
DeletePoints /M=0 item, 1, attach_list, attach_sel
InsertPoints /M=0 dest, 1, attach_list, attach_sel
attach_list[dest][kAttachColName] = name
update_attach_items(logbook)
attach_sel[dest][kAttachColSel] = sel
endif
end
/// button procedure for the attachment up and down buttons
static function bp_attach_updown(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
ControlInfo /w=$ba.win lb_attach
variable row = v_value
dfref df = $s_datafolder
wave /t /sdfr=df attach_list = $s_value
if (cmpstr(ba.ctrlName, "b_attach_up") == 0)
// up button
if (row >= 1)
move_attach_item(logbook, row, -1)
ListBox lb_attach, win=$ba.win, selRow=(row-1)
endif
else
// down button
if (row < DimSize(attach_list, 0) - 1)
move_attach_item(logbook, row, +1)
ListBox lb_attach, win=$ba.win, selRow=(row+1)
endif
endif
break
case -1: // control being killed
break
endswitch
return 0
end
/// button procedure for the Submit and Reply buttons
static function bp_submit(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
string attributes
string message
string graphs
attributes = get_panel_attributes(ba.win)
message = get_panel_message(ba.win)
graphs = get_panel_graphs(ba.win)
if ((scilog_validate_attributes(logbook, attributes, message) == 0))
variable result
result = scilog_create_entry(logbook, attributes, message, graphs=graphs)
if (result == 0)
dfref df = get_scilog_df(logbook, kdfPersistent)
svar /sdfr=df recent
recent = attributes
svar /sdfr=df recent_message
recent_message = message
else
abort "Submission failed. Error code " + num2str(result) + "."
endif
else
abort "Submission failed due to missing/invalid attribute."
endif
break
case -1: // control being killed
break
endswitch
return 0
end
/// select top graph window for attachment
static function bp_attach_top(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string graphs = WinName(0, 1, 1)
set_panel_graphs(ba.win, graphs)
break
case -1: // control being killed
break
endswitch
return 0
end
/// select/deselect all graph windows for attachment
static function bp_attach_allnone(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
dfref df_volatile = get_scilog_df(logbook, kdfVolatile)
wave /sdfr=df_volatile attach_sel
if (cmpstr(ba.ctrlName, "b_attach_all") == 0)
attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] | 16
else
attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] & ~16
endif
break
case -1: // control being killed
break
endswitch
return 0
end
static function bp_save_graphs(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
string graphs = get_panel_graphs(ba.win)
variable ngraphs = ItemsInList(graphs, ";")
variable igraph
string sgraph
string graph_path
for (igraph = 0; igraph < ngraphs; igraph += 1)
sgraph = StringFromList(igraph, graphs, ";")
graph_path = create_graph_file(sgraph, igraph)
if (strlen(graph_path) > 0)
print graph_path
endif
endfor
break
case -1: // control being killed
break
endswitch
return 0
end
static function bp_clear(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
set_panel_attributes(ba.win, "", clear=1)
set_panel_message(ba.win, "")
set_panel_graphs(ba.win, "")
break
case -1: // control being killed
break
endswitch
return 0
end
static function /s get_default_panel_name()
string windowname
windowname = StringFromList(0, WinList("*SciLogPanel*", ";", "WIN:64"), ";")
return windowname
end
/// get a list of attributes from the fields of the SciLog panel.
///
/// @param windowname window name of the SciLog panel
/// if empty, use default name "PearlSciLogPanel"
///
/// @return list of attributes in the format "key1:value1;key2:value2".
///
static function /s get_panel_attributes(windowname)
string windowname
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
endif
if (strlen(windowname) == 0)
return ""
endif
string controls = ControlNameList(windowname, ";")
string attributes = ""
string control
string attribute
variable ico
variable nco = ItemsInList(controls, ";")
for (ico = 0; ico < nco; ico += 1)
control = StringFromList(ico, controls, ";")
attribute = GetUserData(windowname, control, "attribute")
if (strlen(attribute) > 0)
ControlInfo /w=$windowname $control
switch(v_flag)
case 2: // checkbox
attributes = ReplaceNumberByKey(attribute, attributes, v_value, ":", ";")
break
case 3: // popupmenu
case 5: // setvariable
attributes = ReplaceStringByKey(attribute, attributes, s_value, ":", ";")
break
endswitch
endif
endfor
return attributes
end
/// set the fields of the SciLog panel
///
/// @param windowname window name of the SciLog panel
/// if empty, use default name "PearlSciLogPanel"
///
/// @param attributes list of attributes to set (format "key1:value1;key2:value2")
///
/// @param clear what to do if a key is missing in attributes?
/// @arg 0 (default) leave the field unchanged
/// @arg 1 clear the field
///
static function /s set_panel_attributes(windowname, attributes, [clear])
string windowname
string attributes
variable clear
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
endif
if (strlen(windowname) == 0)
return ""
endif
if (ParamIsDefault(clear))
clear = 0
endif
string path
string logbook = GetUserData(windowname, "", "logbook")
dfref df_persistent = get_scilog_df(logbook, kdfPersistent)
string persistent_path = GetDataFolder(1, df_persistent)
svar /sdfr=df_persistent options
string options_path
string controls = ControlNameList(windowname, ";")
string control
string attribute
string value
variable numval
variable ico
variable nco = ItemsInList(controls, ";")
for (ico = 0; ico < nco; ico += 1)
control = StringFromList(ico, controls, ";")
attribute = GetUserData(windowname, control, "attribute")
if (strlen(attribute))
value = StringByKey(attribute, attributes, ":", ";")
if (strlen(value) || clear)
ControlInfo /w=$windowname $control
switch(v_flag)
case 2: // checkbox
numval = NumberByKey(attribute, attributes, ":", ";")
if ((numtype(numval) != 0) && clear)
numval = 0
endif
if (numtype(numval) == 0)
CheckBox $control, value=numval, win=$windowname
endif
break
case 3: // popupmenu
options_path = persistent_path + StringByKey(attribute, options, ":", ";")
svar values = $options_path
numval = WhichListItem(value, values, ";") + 1
if (numval >= 1)
PopupMenu $control, mode=numval, win=$windowname
endif
break
case 5: // setvariable
SetVariable /z $control, value= _STR:value, win=$windowname
break
endswitch
endif
endif
endfor
return attributes
end
/// get the message field of the SciLog panel
///
/// @param windowname window name of the SciLog panel
/// if empty, use default name "PearlSciLogPanel"
///
/// @return message text
///
static function /s get_panel_message(windowname)
string windowname
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
endif
if (strlen(windowname) == 0)
return ""
endif
string nb = windowname + "#Message"
notebook $nb selection={startOfFile, endOfFile}
getselection notebook, $nb, 2
return s_selection
end
/// set the message field of the SciLog panel
///
/// @param windowname window name of the SciLog panel
/// if empty, use default name "PearlSciLogPanel"
///
/// @param message message text that can be passed to the @c Notebook operation.
///
/// @return original message (unchanged)
///
static function /s set_panel_message(windowname, message)
string windowname
string message
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
endif
string nb = windowname + "#Message"
notebook $nb selection={startOfFile, endOfFile},text=message
return message
end
/// get the names of the graphs selected for attachment
///
/// @param windowname panel window name
/// @returns a semicolon-separated list,
/// or the empty string if the selection is not valid.
///
static function /s get_panel_graphs(windowname)
string windowname // panel window name
dfref savedf = getdatafolderdfr()
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
endif
if (strlen(windowname) == 0)
return ""
endif
string logbook = GetUserData(windowname, "", "logbook")
dfref df_volatile = get_scilog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
string graphs = ""
string windows = ""
string graphname
variable n = DimSize(attach_sel, 0)
variable i
for (i = 0; i < n; i += 1)
if (attach_sel[i][kAttachColSel] & 16)
graphname = attach_list[i][kAttachColName]
windows = WinList(graphname, ";", "WIN:1")
if (ItemsInList(windows) == 1)
graphs = AddListItem(graphname, graphs, ";", inf)
endif
endif
endfor
return graphs
end
/// update selection of graphs for attachment
///
/// @param windowname panel window name. looks for default panel if empty.
///
/// @param graphs semicolon-separated list of names of graph windows to select for attachment.
///
static function /s set_panel_graphs(windowname, graphs)
string windowname
string graphs
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
endif
if (strlen(windowname) == 0)
return ""
endif
string logbook = GetUserData(windowname, "", "logbook")
update_attach_items(logbook)
dfref df_volatile = get_scilog_df(logbook, kdfVolatile)
wave /t /sdfr=df_volatile attach_list
wave /sdfr=df_volatile attach_sel
variable n = DimSize(attach_sel, 0)
variable i
string graphname
for (i = 0; i < n; i += 1)
graphname = attach_list[i][kAttachColName]
if (WhichListItem(graphname, graphs)>= 0)
attach_sel[i][kAttachColSel] = 48
else
attach_sel[i][kAttachColSel] = 32
endif
endfor
end