igor-public/pearl/pearl-elog.ipf

1261 lines
36 KiB
Igor

#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma version = 1.2
#pragma IgorVersion = 6.2
#pragma ModuleName = PearlElog
// $Id$
// author: matthias.muntwiler@psi.ch
// Copyright (c) 2013-15 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 ELOG entries with Igor graphs as attachment.
/// @ingroup ArpesPackage
///
/// the functions in this module support the following work flows:
/// 1. send a preview of a selected measurement to ELOG.
/// 2. send any Igor graph to ELOG. (CLI and GUI)
/// 3. direct access to all ELOG parameters. (CLI only)
///
/// the configuration of the ELOG server and logbooks (except user name and password)
/// as well as the most recently used attributes are persisted in the preference file.
///
/// elog command line
///@verbatim
/// elog -h <hostname> [-p port] [-d subdir]
/// Location where elogd is running
/// -l logbook Name of logbook
/// -s Use SSL for communication
/// [-v] For verbose output
/// [-w password] Write password defined on server
/// [-u username password] User name and password
/// [-f <attachment>] Up to 50 attachments
/// -a <attribute>=<value> Up to 50 attributes
/// [-r <id>] Reply to existing message
/// [-q] Quote original text on reply
/// [-e <id>] Edit existing message
/// [-x] Suppress email notification
/// [-n 0|1|2] Encoding: 0:ELcode,1:plain,2:HTML
/// -m <textfile>] | <text>
///@endverbatim
///
/// user name and password are used if configured in the package data folder.
/// there is currently no separate user interface.
///
/// @attention some functions in this module refer specifically to the ELOG configuration at PEARL.
/// logbook and attributes are specific to the ELOG configuration at PEARL.
///
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
///
/// @copyright 2013-15 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 PearlElog
/// @brief interface for writing ELOG entries with Igor graphs as attachment.
///
/// PearlElog is declared in @ref pearl-elog.ipf.
static strconstant package_name = "pearl_elog"
static strconstant package_path = "root:packages:pearl_elog:"
/// main function to initialize ELOG and to open an ELOG 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 ELOG package is initialized (overwriting existing data) but no panel is opened.
///
function pearl_elog(logbook)
string logbook
string win_name = logbook + "ElogPanel"
if (strlen(logbook) > 0)
if (strlen(WinList(win_name, ";", "")) > 0)
DoWindow /F $win_name
else
if (init_package() == 0)
load_prefs()
endif
PearlElogPanel(logbook)
endif
else
init_package(clean=1)
load_prefs()
endif
end
/// save preferences and recent values before Igor opens a new experiment.
static function IgorBeforeNewHook(igorApplicationNameStr)
string igorApplicationNameStr
save_prefs()
return 0
end
/// save preferences and recent values before Igor quits.
static function IgorQuitHook(igorApplicationNameStr)
string igorApplicationNameStr
save_prefs()
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))
init_package(clean=1)
load_prefs()
endif
return 0
end
/// returns the package data folder or logbook datafolder
///
/// @param logbook name of logbook, or empty string for package datafolder
///
/// @returns data folder reference
static function /df get_elog_df(logbook)
string logbook
dfref df_package = $package_path
if (strlen(logbook) > 0)
dfref df_logbook = df_package:$logbook
return df_logbook
else
return df_package
endif
end
/// initialize the package data folder.
///
/// the data folder is initialized with a default, local configuration and the PEARL logbooks.
/// the server configuration should be set in the preferences.
///
/// @remark this function is specific to the setup at PEARL.
static function init_package([clean])
variable clean // 0 (default) = do not overwrite existing data
// 1 = clean configuration, overwrite existing data
if (ParamIsDefault(clean))
clean = 0
endif
dfref savedf = getdatafolderdfr()
dfref basedf = get_elog_df("")
if ((clean == 0) && (DataFolderRefStatus(dfr) == 1))
return 1
endif
setdatafolder root:
newdatafolder /o/s packages
newdatafolder /o/s $package_name
dfref basedf = getdatafolderdfr()
// common configuration (persistent except username and password)
string /g elog_path = "c:\\program files (x86)\\ELOG\\elog.exe"
string /g hostname = "localhost"
variable /g port = 0 // 0 = unspecified (default)
variable /g ssl = 0 // 0 = plain text (incl. passwords), 1 = secure connection
string /g subdir = ""
string /g username = ""
string /g password = ""
// list of configured logbooks
// there must be a sub-folder for each of these
string /g logbooks = "Experiments;Calculations"
// Experiments logbook
setdatafolder basedf
newdatafolder /o/s Experiments
// ELOG logbook name
string /g logbook = "Experiments"
// attributes (persistent)
// available attributes
string /g attributes = "author;project;sample;source;task;technique;valid"
// controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
string /g controls = "sv_author;sv_project;sv_sample;pm_source;pm_task;pm_technique;cb_valid"
// attributes with fixed options, value item declares the options string
string /g options = "source=sources;task=tasks;technique=techniques"
// attributes which must be defined
string /g required_attributes = "author;project;sample;source;task;technique;valid"
// option lists
string /g sources = "Manual Entry;Scienta Data;SScan Data;Prosilica Data;OTF Data;Beamline Status;LEED Data;QMS Data;Matrix Data;Igor Pro;Other"
string /g tasks = "Measurement;Sample Preparation;Sample Storage;Optimization;Analysis;Development;Maintenance;Test;Comment;Other"
string /g techniques = "XPS;UPS;XPD;XAS;XMCD;PhD;ARUPS;LEED;AES;STM;STS;QMS;MBE;Test;Other"
// usage data (persistent)
string /g recent = ""
string /g recent_message = ""
// run-time variables (volatile)
variable /g msg_id
// Calculations logbook
setdatafolder basedf
newdatafolder /o/s Calculations
// ELOG logbook name
string /g logbook = "Calculations"
// attributes (persistent)
// available attributes
string /g attributes = "author;project;sample;program;revision;machine;job;source path;result path;valid"
// controls corresponding to attributes
// prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
string /g controls = "sv_author;sv_project;sv_sample;pm_program;sv_revision;pm_machine;sv_job;sv_sourcepath;sv_resultpath;cb_valid"
// attributes with fixed options, value item declares the options string
string /g options = "program=programs;machine=machines"
// attributes which must be defined
string /g required_attributes = "author;project;sample"
// option lists
string /g programs = "DMSUP;EDAC;MSC;MUFPOT;SSC"
string /g machines = "llcx;Merlin;PC"
// usage data (persistent)
string /g recent = ""
string /g recent_message = ""
// run-time variables (volatile)
variable /g msg_id
setdatafolder savedf
return 0
end
/// set module configuration parameters
function elog_config([elog_path, hostname, port, subdir])
string elog_path
string hostname
variable port
string subdir
dfref saveDF = GetDataFolderDFR()
if (!ParamIsDefault(elog_path))
svar g_elog_path = $(package_path + "elog_path")
g_elog_path = elog_path
endif
if (!ParamIsDefault(hostname))
svar g_hostname = $(package_path + "hostname")
g_hostname = hostname
endif
if (!ParamIsDefault(port))
nvar g_port = $(package_path + "port")
g_port = port
endif
if (!ParamIsDefault(subdir))
svar g_subdir = $(package_path + "subdir")
g_subdir = subdir
endif
setdatafolder savedf
end
/// save persistent package data to the preferences file.
///
/// currently saves everything under the package folder.
static function save_prefs()
dfref saveDF = GetDataFolderDFR()
dfref df = get_elog_df("")
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
setdatafolder root:
NewDataFolder /O/S packages
NewDataFolder /O/S $package_name
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
result = 0
endif
endif
SetDataFolder saveDF
return result
end
/// add a copy of the given graph to ELOG, prompting for attributes (deprecated)
///
/// @deprecated
/// this function is specific to the PEARL/Experiments logbook.
/// it cannot be customized without major efforts.
/// it will be removed in a future version.
function elog_add_graph_prompt(graphname, [replyto])
string graphname
variable replyto
print "executing deprecated function elog_add_graph_prompt."
dfref savedf = getdatafolderdfr()
//setdatafolder root:packages:elog
string attributes
string message = ""
svar mru_attributes = $(package_path + "attributes")
attributes = mru_attributes
variable result = elog_prompt_attributes(attributes, message)
if (result == 0)
if (ParamIsDefault(replyto))
result = elog_create_entry("Experiments", attributes, message, graphs=graphname)
else
result = elog_create_entry("Experiments", attributes, message, graphs=graphname, replyto=replyto)
endif
if (result == 0)
mru_attributes = attributes
endif
endif
setdatafolder savedf
return result
end
/// prompt for attributes (deprecated)
///
/// @deprecated
/// this function is specific to the PEARL/Experiments logbook.
/// it cannot be customized without major efforts.
/// it will be removed in a future version.
function elog_prompt_attributes(attributes, message)
string &attributes
string &message
print "executing deprecated function elog_prompt_attributes."
string author
string project
string sample
string source
string task
string technique
string file
variable valid
string loc_message
author = StringByKey("Author", attributes, "=", ";")
project = StringByKey("Project", attributes, "=", ";")
sample = StringByKey("Sample", attributes, "=", ";")
source = StringByKey("Source", attributes, "=", ";")
task = StringByKey("Task", attributes, "=", ";")
technique = StringByKey("Technique", attributes, "=", ";")
file = StringByKey("File", attributes, "=", ";")
valid = NumberByKey("Valid", attributes, "=", ";")
loc_message = message
svar sources = $(package_path + "sources")
svar tasks = $(package_path + "tasks")
svar techniques = $(package_path + "techniques")
prompt author, "Author"
prompt project, "Project"
prompt sample, "Sample"
prompt source, "Source", popup, sources
prompt task, "Task", popup, tasks
prompt technique, "Technique", popup, techniques
prompt file, "File"
prompt valid, "Valid"
prompt loc_message, "Message"
doprompt "Create New ELOG Entry", author, project, sample, task, technique, file, loc_message
source = "Manual Entry"
if (v_flag == 0)
attributes = ReplaceStringByKey("Author", attributes, author, "=", ";")
attributes = ReplaceStringByKey("Project", attributes, project, "=", ";")
attributes = ReplaceStringByKey("Sample", attributes, sample, "=", ";")
attributes = ReplaceStringByKey("Source", attributes, source, "=", ";")
attributes = ReplaceStringByKey("Task", attributes, task, "=", ";")
attributes = ReplaceStringByKey("Technique", attributes, technique, "=", ";")
attributes = ReplaceStringByKey("File", attributes, file, "=", ";")
//attributes = ReplaceNumberByKey("Valid", attributes, valid, "=", ";")
message = loc_message
endif
return v_flag
end
/// validate attributes
///
/// @returns 0 if all required attributes are present and enumerated items are correct.
/// non-zero if a violation is detected.
///
/// @todo
/// function currently not implemented, always returns 0
function elog_validate_attributes(logbook, attributes)
string logbook // name of the logbook (as in igor folder name)
string attributes // key=value list of attributes, semicolon separated
variable result = 0
return result
end
function elog_create_entry(logbook, attributes, message, [encoding, graphs, replyto])
string logbook
string attributes // key=value list of attributes, semicolon separated
string message
variable encoding // encoding of message, 0:ELcode, 1:plain (default), 2:HTML
string graphs // names of graph windows to be added as attachments, semicolon separated
variable replyto // existing message ID (> 1) to follow up on.
// 0 or default: start new thread
if (ParamIsDefault(encoding))
encoding = 1
endif
if (ParamIsDefault(graphs))
graphs = ""
endif
if (ParamIsDefault(replyto))
replyto = 0
endif
dfref savedf = getdatafolderdfr()
setdatafolder $(package_path)
setdatafolder $(logbook)
variable result = 0
nvar msg_id
if (elog_validate_attributes(logbook,attributes) != 0)
result = -3 // error: invalid/missing attributes
endif
string cmd = prepare_command_line(logbook)
if (strlen(cmd) == 0)
result = -2 // error: invalid/missing command line
endif
if (replyto >= 1)
cmd += " -r " + num2str(replyto)
endif
cmd += " -n " + num2str(encoding)
variable nattr = ItemsInList(attributes, ";")
variable iattr
string sattr
for (iattr = 0; (iattr < nattr) && (result == 0); iattr += 1)
sattr = StringFromList(iattr, attributes, ";")
if (strlen(StringFromList(1, sattr, "=")) > 0)
cmd += " -a \"" + sattr + "\""
endif
endfor
if (result == 0)
string cmd_graphs = prepare_graph_attachments(graphs)
cmd += " " + cmd_graphs
endif
if ((result == 0) && (strlen(message) > 0))
string messagefile = create_message_file(message)
if (strlen(messagefile) > 0)
cmd += " -m \"" + messagefile + "\""
cmd += " > \"" + get_log_path() + "\""
string cmd_file_path = create_cmd_file(cmd)
ExecuteScriptText cmd_file_path
variable id = parse_result()
if (id > 0)
msg_id = id
print "ELOG: sent message " + num2str(id)
else
print "ELOG: sending message failed."
result = -4 // error: elog returned error
endif
cleanup_temp_files()
else
result = -1 // error
endif
endif
setdatafolder savedf
return result
end
/// add one or more graphs to an existing ELOG entry
///
/// @param logbook name of the target logbook
/// @param id identification number of the existing entry
/// @param graphs names of graph windows to be added as attachments, semicolon separated
///
/// @warning this will delete all existing attachments of the entry!
function elog_add_attachment(logbook, id, graphs)
string logbook
variable id // existing entry ID
string graphs // names of graph windows to be added as attachments, semicolon separated
dfref savedf = getdatafolderdfr()
setdatafolder $(package_path)
setdatafolder $(logbook)
variable result = 0
nvar msg_id
string cmd = prepare_command_line(logbook)
if (strlen(cmd) == 0)
result = -2 // error: invalid/missing command line
endif
cmd += " -e " + num2str(id)
if (result == 0)
string cmd_graphs = prepare_graph_attachments(graphs)
if (strlen(cmd_graphs) == 0)
result = -3 // error: invalid/missing graphs
endif
endif
if (result == 0)
cmd += " " + cmd_graphs
cmd += " > \"" + get_log_path() + "\""
string cmd_file_path = create_cmd_file(cmd)
ExecuteScriptText cmd_file_path
id = parse_result()
if (id > 0)
msg_id = id
print "ELOG: attached graphs to message " + num2str(id)
else
print "ELOG: attaching graphs failed."
result = -4 // error: elog returned error
endif
cleanup_temp_files()
endif
setdatafolder savedf
return result
end
/// format the ELOG command and essential address arguments.
///
/// the following arguments are included (from global variables) if applicable:
/// host name, port, SSL, sub-dir, username, password
/// the result string does not include leading or trailing space
///
/// @param logbook name of the target logbook
static function /s prepare_command_line(logbook)
string logbook
dfref savedf = getdatafolderdfr()
setdatafolder $(package_path)
svar elog_path
svar hostname
nvar port
nvar ssl
svar subdir
svar username
svar password
string cmd
cmd = "\"" + elog_path + "\""
cmd += " -h " + hostname
if ((nvar_exists(port)) && (port > 0))
cmd += " -p " + num2str(port)
endif
if ((svar_exists(subdir)) && (strlen(subdir) > 0))
cmd += " -d " + subdir
endif
cmd += " -l \"" + logbook + "\""
if ((nvar_exists(ssl)) && (ssl != 0))
cmd += " -s"
endif
//cmd += " -w " + password
if (svar_exists(username) && svar_exists(password) && (strlen(username) > 0) && (strlen(password) > 0))
cmd += " -u " + username + " " + password
endif
setdatafolder savedf
return cmd
end
/// prepare screenshots of graph windows for attachments
///
/// prepares the attachment files from Igor graph windows
/// and returns the arguments to the elog command to attach the files.
/// the result string does not include leading or trailing space
///
/// @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
dfref savedf = getdatafolderdfr()
setdatafolder $(package_path)
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 += " -f \"" + graph_path + "\""
endif
endfor
setdatafolder savedf
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
static function /s create_message_file(message)
string message
string path = SpecialDirPath("Temporary", 0, 1, 0)
variable len = strlen(path)
if (numtype(len) == 0)
path += "elog_temp_message.txt"
variable f1
Open f1 as path
fprintf f1, message
Close f1
else
path = ""
endif
return path
end
static function /s create_graph_file(graphname, fileindex)
string graphname
variable fileindex
string path = SpecialDirPath("Temporary", 0, 1, 0)
string ts = get_timestamp("_")
variable len = strlen(path)
if (numtype(len) == 0)
path += "elog_" + ts + "_" + num2str(fileindex) + ".png"
SavePICT /B=72 /E=-5 /M /O /W=(0,0,8,6) /WIN=$graphname /Z as path
if (v_flag != 0)
path = ""
endif
else
path = ""
endif
return path
end
static function /s create_cmd_file(cmd)
string cmd
string path = SpecialDirPath("Temporary", 0, 1, 0)
variable len = strlen(path)
if (numtype(len) == 0)
path += "elog_temp_cmd.bat"
variable f1
Open f1 as path
fprintf f1, cmd
Close f1
else
path = ""
endif
return path
end
static function /s get_log_path()
string path = SpecialDirPath("Temporary", 0, 1, 0)
variable len = strlen(path)
if (numtype(len) == 0)
path += "elog.log"
else
path = ""
endif
return path
end
static function /s cleanup_temp_files()
string path = SpecialDirPath("Temporary", 0, 1, 0)
string cmd
sprintf cmd, "del \"%s\elog*.*\"", path
//ExecuteScriptText cmd
return path
end
static strconstant elog_success_msg = "Message successfully transmitted"
static strconstant elog_parse_id = "ID=%u"
/// parse the result file from an elog invokation.
///
/// @returns the ID of the generated message,
/// or a value <= 0 if an error occurred.
static function parse_result()
string path = get_log_path()
string line = ""
variable len = strlen(path)
if (numtype(len) == 0)
variable f1
Open /R/Z f1 as path
if (v_flag == 0)
FReadLine f1, line
Close f1
endif
endif
variable success = 0
variable id = -1
if (strlen(line) > 0)
string part1 = StringFromList(0, line, ",")
string part2 = ReplaceString(" ", StringFromList(1, line, ","), "")
success = cmpstr(part1, elog_success_msg) == 0
if (success)
sscanf part2, elog_parse_id, id
endif
endif
return id
end
/// open a new panel for submitting data to ELOG.
///
/// this function creates only the panel but not the necessary package data folder.
/// call init_package() and load_prefs() once before creating panels.
///
/// @param logbook name of the target logbook
///
function /s PearlElogPanel(logbook)
string logbook
dfref savedf = getdatafolderdfr()
setdatafolder $(package_path)
setdatafolder $(logbook)
string df_path = getdatafolder(1)
string win_name = logbook + "ElogPanel"
string win_title = "ELOG " + logbook
NewPanel /K=1 /N=$win_name /W=(600,200,926,494) as win_title
win_name = s_name
ModifyPanel /w=$win_name cbRGB=(52224,52224,65280)
svar attributes
svar controls
svar options
variable iattr
variable nattr = ItemsInList(attributes, ";")
string s_attr
string s_control
string s_option
string options_path
string variable_path
variable ypos = 2
for (iattr = 0; iattr < nattr; iattr += 1)
s_attr = StringFromList(iattr, attributes, ";")
s_control = StringFromList(iattr, controls, ";")
strswitch(s_control[0,1])
case "sv":
SetVariable $s_control, win=$win_name, pos={0,ypos}, size={260,16}, bodyWidth=200
SetVariable $s_control, win=$win_name, title=s_attr, value= _STR:""
SetVariable $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 18
break
case "pm":
options_path = df_path + StringByKey(s_attr, options, "=", ";")
PopupMenu $s_control, win=$win_name, pos={0,ypos}, size={260,21}, bodyWidth=200
PopupMenu $s_control, win=$win_name, title=s_attr
PopupMenu $s_control, win=$win_name, mode=1, popvalue="Test", value= #options_path
PopupMenu $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 23
break
case "cb":
CheckBox $s_control, win=$win_name, pos={60,ypos}, size={260,14}
CheckBox $s_control, win=$win_name, title=s_attr, value= 1
CheckBox $s_control, win=$win_name, userdata(attribute)=s_attr
ypos += 17
break
endswitch
endfor
PopupMenu pm_attach,win=$win_name, pos={0,ypos},size={260,21},bodyWidth=200,title="Attachment"
PopupMenu pm_attach,win=$win_name, mode=1,popvalue="(none)",value=PearlElog#pm_list_attach_items()
PopupMenu pm_attach,win=$win_name, help={"Choose any visible Igor graph for attachment."}
Button b_select_attach_top,win=$win_name, pos={264,ypos},size={60,20},proc=PearlElog#bp_select_attach_top,title="Top Graph"
Button b_select_attach_top,win=$win_name, help={"Select top graph window."}
Button b_select_attach_top,win=$win_name, fcolor=(56576,60928,47872)
ypos += 246-160
Button b_submit,win=$win_name, pos={60,ypos},size={46,20},proc=PearlElog#bp_submit,title="Submit"
Button b_submit,win=$win_name, help={"Submit form data to ELOG (new entry)."}
Button b_submit,win=$win_name, fcolor=(56576,60928,47872)
Button b_clear,win=$win_name, pos={110,ypos},size={46,20},proc=PearlElog#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
variable_path = df_path + "msg_id"
SetVariable sv_id,win=$win_name, pos={46,ypos},size={109,16},bodyWidth=94
SetVariable sv_id,win=$win_name, title="ID",value=$variable_path
SetVariable sv_id,win=$win_name, help={"ID of last submitted message, or message to attach or reply to."}
ypos += 270-272
Button b_attach,win=$win_name, pos={160,ypos},size={48,20},proc=PearlElog#bp_attach,title="Attach"
Button b_attach,win=$win_name, help={"Attach the selected graph to an existing ELOG entry (correct ID required)."}
Button b_attach,win=$win_name, fcolor=(56576,60928,47872)
Button b_reply,win=$win_name, pos={210,ypos},size={48,20},proc=PearlElog#bp_submit,title="Reply"
Button b_reply,win=$win_name, help={"Submit form data to ELOG as a reply to an existing message (correct ID required)."}
Button b_reply,win=$win_name, fcolor=(56576,60928,47872)
ypos += 184-270
TitleBox t_message,win=$win_name, pos={0,ypos},size={58,16},fixedSize=1,frame=0,anchor=RT,title="Message"
SetWindow $win_name, hook(elogPanelHook)=PearlElog#elog_panel_hook
SetWindow $win_name, userdata(logbook)=logbook
DefineGuide UGH0={FT,ypos},UGV0={FL,60},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 font="Arial", fSize=10, fStyle=0, textRGB=(0,0,0)
RenameWindow #,Message
SetActiveSubwindow ##
// restore recently used attributes and message
svar /z /sdfr=get_elog_df(logbook) recent
if (svar_exists(recent) && (strlen(recent) > 0))
set_panel_attributes(win_name, recent)
endif
svar /z /sdfr=get_elog_df(logbook) recent_message
if (svar_exists(recent_message) && (strlen(recent_message) > 0))
set_panel_message(win_name, recent_message)
endif
setdatafolder savedf
return win_name
end
static function elog_panel_hook(s)
STRUCT WMWinHookStruct &s
Variable hookResult = 0
switch(s.eventCode)
case 6: // resize
// move bottom-aligned controls when the window is resized
variable b_top = s.winRect.bottom + 4
Button b_submit,pos={60,b_top}
Button b_clear,pos={110,b_top}
b_top += 24
Button b_attach,pos={160,b_top}
Button b_reply,pos={210,b_top}
b_top += 2
SetVariable sv_id,pos={46,b_top}
break
endswitch
return hookResult // 0 if nothing done, else 1
end
/// get a list of graph windows for a popup menu.
static function /s pm_list_attach_items()
// get graph names
string names = WinList("*", ";", "WIN:1;VISIBLE:1")
names = SortList(names, ";", 16)
// get corresponding graph titles
variable nnames = ItemsInList(names, ";")
variable iname
string name
string item
string items = ""
// format each entry like "name: title"
for (iname = 0; iname < nnames; iname += 1)
name = StringFromList(iname, names, ";")
getwindow /z $name, wtitle
if (v_flag == 0)
item = ReplaceString(";", s_value, ", ") // title
item = item + " (" + name + ")"
items = AddListItem(item, items, ";", inf)
endif
endfor
items = AddListItem("(none)", items, ";")
return items
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)
variable id
if (cmpstr(ba.ctrlName, "b_reply") == 0)
// Reply button
ControlInfo /w=$ba.win sv_id
id = v_value
else
// Submit button
id = 0
endif
if ((elog_validate_attributes(logbook, attributes) == 0) && (strlen(message) > 0))
variable result
result = elog_create_entry(logbook, attributes, message, graphs=graphs, replyto=id)
if (result == 0)
svar /sdfr=get_elog_df(logbook) recent
recent = attributes
svar /sdfr=get_elog_df(logbook) 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_select_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
static function bp_attach(ba) : ButtonControl
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
string logbook = GetUserData(ba.win, "", "logbook")
string graphs
graphs = get_panel_graphs(ba.win)
variable id
ControlInfo /w=$ba.win sv_id
id = v_value
// TODO : is there a way around this restriction?
DoAlert /T="ELOG" 1, "This operation will replace all existing attachments. Do you want to continue?"
if ((id > 0) && (v_flag == 1))
variable result
result = elog_add_attachment(logbook, id, graphs)
if (result != 0)
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
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("*ElogPanel*", ";", "WIN:64"), ";")
return windowname
end
/// get a list of attributes from the fields of the ELOG panel.
///
/// @param windowname window name of the ELOG panel
/// if empty, use default name "PearlElogPanel"
///
/// @return list of attributes to in the format <code>"key1=value1;key2=value2"</code>.
///
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 ELOG panel
///
/// @param windowname window name of the ELOG panel
/// if empty, use default name "PearlElogPanel"
///
/// @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 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
PopupMenu $control, popvalue=value, win=$windowname
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 ELOG panel
///
/// @param windowname window name of the ELOG panel
/// if empty, use default name "PearlElogPanel"
///
/// @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 ELOG panel
///
/// @param windowname window name of the ELOG panel
/// if empty, use default name "PearlElogPanel"
///
/// @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
///
/// @returns a semicolon-separated list,
/// or the empty string if the selection is not valid.
///
/// in the current version, the function returns at most one graph.
/// in future versions, the function may return more than one graph.
///
static function /s get_panel_graphs(windowname)
string windowname // panel window name
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
endif
if (strlen(windowname) == 0)
return ""
endif
ControlInfo /W=$windowname pm_attach
// menu item has the form: "title (name)"
string graphname = ReplaceString(")", StringFromList(ItemsInList(s_value, "(") - 1, s_value, "("), "")
string graphs = ""
string windows = WinList(graphname, ";", "WIN:1")
if (ItemsInList(windows) == 1)
graphs = graphname
else
graphs = ""
endif
return graphs
end
static function /s set_panel_graphs(windowname, graphs)
string windowname // panel window name. looks for default panel if empty.
string graphs // name of graph window to select for attachment.
if (strlen(windowname) == 0)
windowname = get_default_panel_name()
endif
if (strlen(windowname) == 0)
return ""
endif
// the panel supports only one graph
string graph = StringFromList(0, graphs, ";")
string items = pm_list_attach_items()
string item
string itemname
variable nitems = ItemsInList(items, ";")
variable iitem
for (iitem = 0; iitem < nitems; iitem += 1)
item = StringFromList(iitem, items, ";")
itemname = ReplaceString(")", StringFromList(ItemsInList(item, "(") - 1, item, "("), "")
if (cmpstr(graph, itemname) == 0)
iitem += 1
PopupMenu pm_attach mode=iitem, win=$windowname
break
endif
endfor
return graph
end