TCL/TK Radiobutton with a Dynamic Variable Name in - variables

I am trying to create a TK GUI in TCL that will provide users with the ability to see the current value of a configuration file. This GUI will provide the user the ability to change the config files values to enabled or disabled from radio buttons in the GUI. My configuration file will be a variable length because addition items can be added and I need the GUI to build based on the number of entries in the file. To accomplish this I am trying to loop through the configuration file when creating the GUI and using a variable for each set of radio buttons that can define the user selected value for each Item in the config file.
The configuration file is a simple interface to have the items name associated with a enable (E) or disable (D) value.
Item1 D
Item2 E
Item3 D
Below is the code that I have to generate the radio button for each item in the config with the option to Enable, Disable, or No Change. Here I am trying to create the dynamic variable for each item that will store the selection of the radio button. Besides the current code below I also tried other variations such as -variable selItem${mVal}.
label .optionSelection.c${mVal}_1 -text $mVal
radiobutton .optionSelection.c${mVal}_2 -text "Enable" -variable selItem$mVal \
-value "Enable" -justify left
radiobutton .optionSelection.c${mVal}_3 -text "Disable" -variable selItem$mVal \
-value "Disable" -justify left
radiobutton .optionSelection.c${mVal}_4 -text "No Change" -variable selItem$mVal \
-value "No Change" -justify left
label .optionSelection.c${mVal}_5 -text [dict get $configDict $mVal] \
-textvariable curState${mVal}_5
To get the value of the selItem$mVal (selItemItem1) I have tried to get the value to print with the line below. I have different combination of parenthesis and brackets to create the variable $selItemItem1 so that I can get the value of the selected radio button for that item.
puts "$mVal Variable is $selItem$mVal"
Right now I am just trying to get the variable to print so that I can make it global and reference the value in other procs in the code. I did some research into using either arrays or dictionaries as the variables for the radio buttons. These methods seem like they would be cleaner but I was unable to find examples of how an array or dictionary can be set by the variable.
References Used
tcl: how to use the value of a variable to create a new variable
TCL, How to name a variable that includes another variable
https://www.tutorialspoint.com/tcl-tk/tcl_variables.htm

You definitely want to be using arrays here. To use an array, simply use arrayname($index) as the variable name, and use $arrayname($index) to access the value in the array.
Below is a simple proof of concept on how one might go about writing a configuration screen. I used an = sign in the configuration file to separate the label from the value rather than a space. This code will not work properly if the value contains an = sign.
I also added some descriptive names to display for the user.
This can be expanded on to allow for other types of configuration options, definitely change to present a better user experience, etc.
package require Tk
proc init { } {
global config
global descriptions
set descriptions(Item1) {Item 1 Label}
set descriptions(Item2) {Config B}
set descriptions(Item3) {Item 3}
foreach name [array names descriptions] {
set config($name) D
}
}
proc displayOptions { } {
global config
global descriptions
ttk::frame .optionSel
ttk::label .optionSel.empty -text {}
ttk::label .optionSel.head_on -text On
ttk::label .optionSel.head_off -text Off
grid .optionSel
grid .optionSel.empty .optionSel.head_on .optionSel.head_off
set fh [open t.txt r]
while { [gets $fh line] >= 0 } {
lassign [split $line =] name value
set config($name) $value
}
close $fh
foreach name [array names descriptions] {
ttk::label .optionSel.lab${name} -text $descriptions($name)
ttk::radiobutton .optionSel.c${name}_on -value E -variable config($name)
ttk::radiobutton .optionSel.c${name}_off -value D -variable config($name)
grid .optionSel.lab${name} .optionSel.c${name}_on .optionSel.c${name}_off \
-sticky w
}
ttk::button .optionSel.save -text { Save } -command ::saveOptions
grid .optionSel.save
}
proc saveOptions { } {
global descriptions
global config
set fh [open t.txt w]
foreach name [array names descriptions] {
puts $fh "$name=$config($name)"
}
close $fh
}
init
displayOptions

Related

Failed to create dynamic variable

I'm trying to create the same numbered variable, but there's something that stops it. But I haven't figured out what it could be yet.
i.e.
set txt0 ""
set txt1 ""
set txt3 ""
So I'm trying to do this dynamically with every click on the button. See my code:
frame .top.tab
button .top.tab.btnTab -text "+" -command { bell ; add }
frame .top.tool
.top.tool configure -relief "raised"
frame .top.panel
.top.panel configure -bg "white"
set n 0
proc add {} {
global n
set txt$n ""
entry .top.tool.ent$n -textvar txt$n
button .top.tool.btn$n -text txt$n -command " remove $n ; .top.panel.lbl$n config -textvar $txt$n "
pack .top.tool.ent$n .top.tool.btn$n -side left
incr n
label .top.panel.lbl$n -text "" -bg "white"
pack .top.panel.lbl$n -fill both -expand yes -anchor e
}
pack .top.tab -side top -fill x -anchor nw
pack .top.tab.btnTab -side right
proc remove { number } {
set total 2
for { set i 0 } { $i < $total } { incr i } {
pack forget .top.panel.lbl$i
}
pack forget .top.panel.lbl$total
pack .top.panel.lbl$number -fill both -expand yes -anchor e
}
pack .top.tool -side top -fill x -anchor nw
pack .top.panel -side top -fill both -expand yes -anchor sw
What could it be?
I know this around the variable $txt$n
You're creating a local variable with the name you want, but Tk won't bind anything to local variables as widgets typically outlast stack frames. You also want to be careful about when you are dealing with the name of a variable versus the current content of the variable.
In the simple case, the best approach is to use an element of a global array:
proc add {} {
global n txt
set txt($n) ""
entry .top.tool.ent$n -textvar txt$n
button .top.tool.btn$n -text txt$n -command \
" remove $n ; .top.panel.lbl$n config -textvar txt($n) "
pack .top.tool.ent$n .top.tool.btn$n -side left
incr n
label .top.panel.lbl$n -text "" -bg "white"
pack .top.panel.lbl$n -fill both -expand yes -anchor e
}
In more complex cases, consider using a TclOO object to hold the state; handles to those are usually "simple" words (unless you take special steps to make them not be; most programmers simply aren't that devious normally).
With the observation and suggestions given in the response of Donal Fellows, I did the necessary changes and worked as expected. In the lines where the property -textvar has just been able to make the exchange of its value by the txt($n) variable that Donal Fellows pointed at the answer. But it has not worked out in my code, since I had to make another change incr n, change its position of the middle of the logic to the end of the proc add scope was vital. Ready, the logic worked as expected. Thanks in advance.
before
after

Select all alias on modifySSLConfig using JACL script

I would want to edit all of the SSL configurations on all of my alias. I have found some resources to do this and my code so far is
$AdminTask modifySSLConfig {-alias NodeDefaultSSLSettings -sslProtocol TLSv1.2}
$AdminConfig save
I would want to be able to do this on all of the alias that can be found on my server, but I don't know how
Any ideas or leads on how to do this will help. Thank you.
Edit:
I am now able to find all of the SSL configs by using this code
[$AdminTask listSSLConfigs {-scopeName (cell):Node01Cell:(node):Node01}
My next problem is, how would I be able to extract the alias string from there? I would only need the alias so that I can replace it on another variable so that I can just use a foreach loop for this
$AdminTask modifySSLConfig {-alias ${aliasvariablegoeshere} -sslProtocol TLSv1.2}
EDIT :
set hold [list [$AdminTask listSSLConfigs {-scopeName (cell):Node01Cell:(node):Node01}]]
foreach aliasList [$AdminConfig show $hold] {
foreach aliasName [$AdminConfig show $aliasList] {
set testTrim "alias "
set test5 [string trimleft $aliasName $testTrim]
$AdminTask modifySSLConfig {-alias ${test5} -sslProtocol TLSv1.2}
}
}
$AdminControl save
I have done this and was able to extract just the alias name and was able to put it on the variable like I wanted, but it gives me an invalid parameter error. Any ideas why this is happening and how would I be able to resolve this?
You can list all the SSL configs using:
AdminTask.listSSLConfigs('[-all true]')
for JACL use:
$AdminTask listSSLConfigs {-all true}
and then iterate over the list and change whatever you need.
Instead of -all you can provide scope for example: -scopeName (cell):localhostNode01Cell:(node):localhostNode01
For details about SSLConfig commands check SSLConfigCommands command group for the AdminTask object
UPDATE:
in general this should work:
foreach aliasList [$AdminTask listSSLConfigs {-scopeName (cell):PCCell1:(node):Node1}] {
puts $aliasList
set splitList [split $aliasList " "]
puts $splitList
set aliasname [lindex $splitList 1]
puts $aliasname
$AdminTask modifySSLConfig { -alias $aliasname -sslProtocol TLSv1.2 }
}
but I cannot make $AdminTask to correctly resolve $aliasname param...
Strongly suggest you to switch to jython. ;-)
I have managed to make it work, it seems like whatever I do I can't make the alias that I got to be a valid parameter so I made the whole thing as a string command instead. Here is my code.
foreach aliasList [$AdminConfig list SSLConfig] {
foreach aliasName [$AdminConfig show $aliasList alias] {
set strTrim "alias "
set strFinal [string trimleft $aliasName $strTrim]
set command "-alias $strFinal -sslProtocol TLSv1.2"
$AdminTask modifySSLConfig $command
puts saved
}
}
$AdminConfig save
I was able to figure it out for Jython:
import sys
import os
import string
import re
#$HOME/IBM/WebSphere/AppServer/bin/wsadmin.sh -lang jython -f $HOME/tls12.py
#Updates Websphere security to TLSv1.2
AdminTask.convertCertForSecurityStandard('[-fipsLevel SP800-131 -signatureAlgorithm SHA256withRSA -keySize 2048 ]')
AdminConfig.save()
AdminNodeManagement.syncActiveNodes()
sslConfigList=AdminTask.listSSLConfigs('[-all true]').splitlines()
for sslConfig in sslConfigList:
sslElems=sslConfig.split(" ")
AdminTask.modifySSLConfig (['-alias',sslElems[1],'-scopeName',sslElems[3],'-sslProtocol', 'TLSv1.2', '-securityLevel', 'HIGH' ])
AdminConfig.save()
AdminNodeManagement.syncActiveNodes()
After that you should also update all your ssl.client.props files with:
com.ibm.ssl.protocol=TLSv1.2
Restart your deployment manager and force manual syncNode on all nodes, for example:
~/IBM/WebSphere/AppServer/profiles/*/bin/syncNode.sh <DeplymentManagerHost> <dmgr port=8879> -username <username> -password <password>

Terraform template_file get pass all received variables to a function

is there in Terraforom in template_files a way to pass through all the received variables to other place?
I mean something similar than $# in bash.
For example:
resource "template_file" "some_template" {
template = "my_template.tpl")}"
vars {
var1 = "value1"
var2 = "value2"
}
}
and then from the rendered file:
#!/bin/bash
echo "Var1: ${var1}"
echo "Var2: ${var2}"
echo "But I want it in someway similar to this:"
for v in $#; do
echo "$v";
done
According to the documentation, no.
From https://www.terraform.io/docs/providers/template/d/file.html
Variables for interpolation within the template. Note that variables
must all be primitives. Direct references to lists or maps will cause
a validation error.
Primitives in terraform are string, number and boolean.
So it means you can not pass a hash or a list to group all the variables in one.
Use join and pass all the variables as one and parse/split them within a script (with tr/IFS tricks)
join("; ", [var.myvar1, var.myvar2, var.myvar3])
and then
IN="${allvars}"
IFS=';' read -ra ADDR <<< "$IN"
for i in "${ADDR[#]}"; do
echo "$i"
done

How to get/set Trello custom fields using the API?

I'm already in love with the Custom Fields feature in Trello. Is there a way to get and set custom fields via the API?
I tried using the get field API call to get a field (on a board with a custom field defined called "MyCustomField"):
curl "https://api.trello.com/1/cards/57c473503a5ef0b76fddd0e5/MyCustomField?key=${TRELLO_API_KEY}&token=${TRELLO_OAUTH_TOKEN}"
to no avail.
The Custom Fields API from Trello is now officially available (announcement blog post here).
It allows users to manipulate both custom field items of boards and custom field item values on cards.
Custom Fields API documentation
Getting customFieldItems For Cards
Setting & Updating CustomFieldItems
This is just to add to bdwakefield's answer. His solution involves hard coding the names of the field ids.
If you want to also retrieve the name of the fields themselves (for example get that "ZIn76ljn-4yeYvz" is actually "priority" in Trello, without needing to hard code it, call the following end point:
boards/{trello board id}/pluginData
This will return an array with the plugins information and in one of the array items, it will include a line along the lines of:
[value] => {"fields":[{"n":"~custom field name~:","t":0,"b":1,"id":"~custom field id that is the weird stuff at the card level~","friendlyType":"Text"}]}
So you just need to figure out the plugin for custom fields in your case, and you can retrieve the key -> value pair for the custom field name and the id associated with it.
It means that if you add / remove fields, or rename them, you can handle it at run time vs changing your code.
This will also give you the options for the custom field (when it is a dropdown like in bdwakefield's example above).
So I have a "sort of" answer to this. It requires some hackery on your part to make it work and there is more than a little manual upkeep as you add properties or values -- but it works.
I am doing this in powershell (I am NOT well versed in ps just yet and this my first really 'big' script that I have pulled together for it) since my intent is to use this with TFS Builds to automate moving some cards around and creating release notes. We are using custom fields to help us classify the card and note estimate/actual hours etc. I used this guys work as a basis for my own scripting. I am not including everything but you should be able to piece everything together.
I have left out everything with connecting to Trello and all that. I have a bunch of other functions for gettings lists, moving cards, adding comments etc. The ps module I linked above has a lot of that built in as well.
function Get-TrelloCardPluginData
{
[CmdletBinding()]
param
(
[Parameter(Mandatory,ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[Alias('Id')]
[string]$CardId
)
begin
{
$ErrorActionPreference = 'Stop'
}
process
{
try
{
$uri = "$baseUrl/cards/$CardId/pluginData?$($trelloConfig.String)"
$result = Invoke-RestMethod -Uri $uri -Method GET
return $result
}
catch
{
Write-Error $_.Exception.Message
}
}
}
You'll get data that looks like this:
#{id=582b5ec8df1572e572411513; idPlugin=56d5e249a98895a9797bebb9;
scope=card; idModel=58263201749710ed3c706bef;
value={"fields":{"ZIn76ljn-4yeYvz":2,"ZIn76ljn-c2yhZH":1}};
access=shared}
#{id=5834536fcff0525f26f9e53b; idPlugin=56d5e249a98895a9797bebb9;
scope=card; idModel=567031ea6a01f722978b795d;
value={"fields":{"ZIn76ljn-4yeYvz":4,"ZIn76ljn-c2yhZH":3}};
access=shared}
The fields collection is basically key/pair. The random characters correspond to the property and the value after that is what was set on the custom property. In this case it is an 'index' for the value in the dropdown. These two fields have a 'priority' (low, medium, high) and a 'classification' (Bug, Change Request, etc) for us. (We are using labels for something else).
So you'll have to create another fucntion where you can parse this data out. I am sure there are better ways to do it -- but this is what I have now:
function Get-TrelloCustomPropertyData($propertyData)
{
$data = $propertyData.Replace('{"fields":{', '')
$data = $data.Replace('}}', '')
$data = $data.Replace('"', '')
$sepone = ","
$septwo = ":"
$options = [System.StringSplitOptions]::RemoveEmptyEntries
$obj = $data.Split($sepone, $options)
$cardCustomFields = Get-TrelloCustomFieldObject
foreach($pair in $obj)
{
$field = $pair.Split($septwo,$options)
if (-Not [string]::IsNullOrWhiteSpace($field[0].Trim()))
{
switch($field[0].Trim())
{
'ZIn76ljn-4yeYvz' {
switch($field[1].Trim())
{
'1'{
$cardCustomFields.Priority = "Critical"
}
'2'{
$cardCustomFields.Priority = "High"
}
'3'{
$cardCustomFields.Priority = "Medium"
}
'4'{
$cardCustomFields.Priority = "Low"
}
}
}
'ZIn76ljn-c2yhZH' {
switch($field[1].Trim())
{
'1'{
$cardCustomFields.Classification = "Bug"
}
'2'{
$cardCustomFields.Classification = "Change Request"
}
'3'{
$cardCustomFields.Classification = "New Development"
}
}
}
'ZIn76ljn-uJyxzA'{$cardCustomFields.Estimated = $field[1].Trim()}
'ZIn76ljn-AwYurD'{$cardCustomFields.Actual = $field[1].Trim()}
}
}
}
return $cardCustomFields
}
Get-TrelloCustomFieldObject is another ps function that I set up to build an object based on the properties I know that I have defined.
function Get-TrelloCustomFieldObject
{
[CmdletBinding()]
param()
begin
{
$ErrorActionPreference = 'Stop'
}
process
{
$ccf = New-Object System.Object
$ccf | Add-Member -type NoteProperty -name Priority -value "None"
$ccf | Add-Member -type NoteProperty -name Classification -value "None"
$ccf | Add-Member -type NoteProperty -name Estimated -value ""
$ccf | Add-Member -type NoteProperty -name Actual -value ""
return $ccf
}
}

How to make a window return value when closed in Tcl/Tk

I have a proc that creates a new window, asking the user to give a database name.. And I want the function, after it's closed to return a value.
How do I make a window to return a value to it's calling proc? I tried calling it using:
puts "dbug:: [set top [new_db_window]]"
The puts is to see the result. It doesn't work. Prints an empty sting ("dbug::") as the window is created and an error "can't read "::new_db_window": no such variable" when I hit the 'ok' button.
The code for the proc is:
proc new_db_window {} {
toplevel .new_db_menu
wm title .new_db_menu "New Data Base"
# Main Frame
frame .new_db_menu.frm -relief "groove" -bd 2
grid .new_db_menu.frm
if {[info exists db_name]} {
unset db_name
}
set ::new_db_window:db_name "Data_Base"
# The Name Entry
set frm_top [frame .new_db_menu.frm.top]
set lbl [label .new_db_menu.frm.top.label -text "Database Name:" -width 15]
set entr [entry .new_db_menu.frm.top.entry -textvariable ::new_db_window:db_name -width 15]
# The buttons
set b_ok [button .new_db_menu.frm.ok -image icon_v -command {return [new_db_ok_button]}]
set b_no [button .new_db_menu.frm.cancel -image icon_x -command {new_db_cancel_button}]
set sep_w [label .new_db_menu.frm.sep_w -text "" -width 1]
set sep_e [label .new_db_menu.frm.sep_e -text "" -width 1]
grid $lbl -row 1 -column 1 -sticky w
grid $entr -row 1 -column 2 -sticky w
grid $frm_top -row 1 -column 1 -columnspan 4
grid $sep_w -row 2 -column 1 -sticky w
grid $b_ok -row 2 -column 2 -sticky w
grid $b_no -row 2 -column 3 -sticky e
grid $sep_e -row 2 -column 4 -sticky e
bind .new_db_menu <Key-KP_Enter> {return [new_db_ok_button]}
bind .new_db_menu <Return> {return [new_db_ok_button]}
bind .new_db_menu <Escape> {new_db_cancel_button}
# catch presses on the window's `x` button
wm protocol .new_db_menu WM_DELETE_WINDOW {
new_db_cancel_button
}
# make the top window unusable
focus $entr
grab release .
grab set .new_db_menu
}
proc new_db_ok_button {} {
new_db_cancel_button
return "$::new_db_window:db_name"
}
proc new_db_cancel_button {} {
grab set .
destroy .new_db_menu
}
One way would be to just use tkwait window $yourwindow to wait until the user closes the window. The window itself should probably use some variable passed to it by the client code to manage user input. For instance, if you need the user to input a database name, use the entry widget and bind it to a variable using its -textvariable option. After the window is closed, and tkwait in the client code returns, read the value of that variable.
Another approach is to not use modal windows and turn into event-driven control flow. That is, make your inquiry window to receive the name of a procedure which should be called when the user accepts its input (and that input is validated) and do any further processing there instead of posting a window and waiting until the user deals with it.
The relevant manual pages are: tkwait and options (for -textvariable).