Syntax Highlighing:
comments, key words, predefined symbols, class members & methods, functions & classes
# URLS.SML - Pops up a dialog that opens the external browser to the url selected.
# Which URLs get displayed is based on where the user clicked.
# The URLs are stored in the reference file url.txt in the same directory as this script.
# Requires TNTmips version 6.4
# Format for reference file:
# [filename : description]
# {element} # element is either "raster value" or a vector element
# ... # of the form "(element type) (table name) (field name) (field value)"
# {element} # (See sample reference file)
# url
# ...
# url
# The following symbols are predefined
# class GROUP Group {use to access the group being viewed if the script is run from a group view}
# class VIEW View {use to access the view the tool script is attached to}
# Variable declarations
class Widget listParent;
class XmForm form, buttonRow;
class XmRowColumn vectorModes, actions;
class XmSeparator line1, line2;
class XmList list;
class XmLabel vectorLabel, actionLabel;
class XmToggleButton pointButton, nodeButton, lineButton, polyButton;
class XmToggleButton scanButton, addButton;
class PushButtonItem urlButton, openButton, closeButton;
class XmDrawingArea da;
class GC gc;
class PointTool pointTool;
class MdispRegionTool polyTool;
string filepath$, mode$, action$;
VECTOR vv;
RASTER rv;
array numeric arr[1000];
numeric elemNum;
numeric setDefaultWhenClose;
# Callback for drawing area expose. Draws text.
proc cbRedraw() {
if (gc == 0) return;
ActivateGC(gc);
SetColorName("gray75");
FillRect(0, 0, da.width, da.height);
SetColorName("black");
DrawInterfaceText("Layer: " + Group.ActiveLayer.Name + "\nURL File: " + filepath$, 0, 10);
}
# Callback for when the active layer changes.
proc cbLayer() {
if (Group.ActiveLayer.Type == "Raster") {
vectorLabel.Sensitive = 0;
pointButton.Sensitive = 0;
nodeButton.Sensitive = 0;
lineButton.Sensitive = 0;
polyButton.Sensitive = 0;
}
else {
vectorLabel.Sensitive = 1;
polyButton.Sensitive = 1;
lineButton.Sensitive = 1;
nodeButton.Sensitive = 1;
pointButton.Sensitive = 1;
}
cbRedraw();
}
# Callback for when the open button is pressed.
proc cbOpen() {
filepath$ = GetInputFileName(filepath$, "Open URL file", "txt");
cbRedraw();
}
# Callback for when the go button is pressed.
proc cbGo() {
local string url$;
url$ = list.GetItemAtPos(list.GetFirstSelectedPos());
if (list.SelectedItemCount > 0 and url$ != "No URLs found!" and url$ != "Type not supported!"
and url$ != "No element found!" and url$ != "File not found!")
RunAssociatedApplication(url$);
}
# Callback for when the close button is pressed.
proc cbClose() {
pointTool.Managed = 0;
DialogClose(form);
if (setDefaultWhenClose) {
setDefaultWhenClose = false;
View.SetDefaultTool();
}
}
# Callback for when user selects a different vector selection mode.
proc cbModeChanged() {
if (pointButton.Set == 1) {
mode$ = "point";
}
else if (nodeButton.Set == 1) {
mode$ = "node";
}
else if (lineButton.Set == 1) {
mode$ = "line";
}
else mode$ = "poly";
}
# Callback for when user selects a different action.
proc cbActionChanged() {
if (scanButton.Set == 1) {
action$ = "scan";
}
else action$ = "add";
}
# Callback for when user clicks the right mouse button on the polygon tool
# (or clicks apply).
proc cbToolApply(class PointTool pointTool) {
# Clear the list
list.DeleteAllItems();
# Set up local variables.
local string url$, layerName$, temp$, temp2$, item$, element$, table$, field$, value$;
local class FILE reffile;
local class GRE_LAYER layer;
local numeric numTok, i, j, num, start;
local class POINT2D point;
local class StatusHandle status;
local class StatusContext context;
layer = Group.ActiveLayer;
# If the layer is a raster or vector, proceed with the script.
if (layer.Type == "Raster" or layer.Type == "Vector") {
# Check point.
point.x = pointTool.Point.x;
point.y = pointTool.Point.y;
# Set up layer, object, layer name, and point transformations.
if (layer.Type == "Raster") {
point = TransPoint2D(point, ViewGetTransLayerToScreen(View, layer, 1));
DispGetRasterFromLayer(rv, layer);
layerName$ = "[" + rv.$Info.Name + " : " + rv.$Info.Desc + "]";
}
else if (layer.Type == "Vector") {
point = TransPoint2D(point, ViewGetTransViewToScreen(View, 1));
point = TransPoint2D(point, ViewGetTransMapToView(View, layer.Projection, 1));
local class GRE_LAYER_VECTOR vl;
vl = layer;
DispGetVectorFromLayer(vv, layer);
layerName$ = "[" + vv.$Info.Name + " : " + vv.$Info.Desc + "]";
}
reffile = fopen(filepath$);
# Find file entry.
start = 0;
while(!feof(reffile)) {
url$ = fgetline$(reffile);
start += 1;
if (url$ == layerName$)
break;
}
if (url$ != layerName$)
list.AddItem("File not found!");
# Read lines for this file.
url$ = "";
while(!feof(reffile)) {
temp$ = fgetline$(reffile);
url$ = url$ + temp$ + "\n";
if (temp$ == "")
break;
}
# Close file.
fclose(reffile);
# Add non-specific URLs to the list.
numTok = NumberTokens(url$, "\n\r");
for i = 1 to numTok {
item$ = GetToken(url$, "\n\r", i);
if (left$(item$, 1) == "{")
break;
if (!list.ItemExists(item$))
list.AddItem(item$);
start += 1;
}
# Remove non-specific URLs from string.
temp$ = "";
for j = i to numTok
temp$ = temp$ + GetToken(url$, "\n\r", j) + "\n";
url$ = temp$;
# If the string is empty, break out of the if statement.
if (url$ == "")
break;
# Set loop variables.
numeric add = false;
numTok = NumberTokens(url$, "\n\r");
# If the layer is vector and an appropriate element exists or the layer is a raster
# and the cell value is not null, search the rest of the string.
if ((layer.Type == "Vector" and ((mode$ == "point" and vv.$Info.NumPoints > 0) or
(mode$ == "node" and vv.$Info.NumNodes > 0) or
(mode$ == "line" and vv.$Info.NumLines > 0) or
(mode$ == "poly" and vv.$Info.NumPolys > 0))) or
(layer.Type == "Raster" and !IsNull(rv[point.y, point.x]))) {
# If the layer is a vector, find and highlight the closest element.
numeric elementNum;
if (layer.Type == "Vector") {
if (mode$ == "point") {
elementNum = FindClosestPoint(vv, point.x, point.y, GetLastUsedGeorefObject(vv));
vl.Point.HighlightSingle(elementNum);
}
else if (mode$ == "node") {
elementNum = FindClosestNode(vv, point.x, point.y, GetLastUsedGeorefObject(vv));
vl.Node.HighlightSingle(elementNum);
}
else if (mode$ == "line") {
elementNum = FindClosestLine(vv, point.x, point.y, GetLastUsedGeorefObject(vv));
vl.Line.HighlightSingle(elementNum);
}
else {
elementNum = FindClosestPoly(vv, point.x, point.y, GetLastUsedGeorefObject(vv));
vl.Poly.HighlightSingle(elementNum);
}
}
# Create a status bar so user knows the script is doing something.
status = StatusDialogCreate(form);
context = StatusContextCreate(status);
StatusSetMessage(context, "Scanning File...");
for i = 1 to numTok {
temp$ = GetToken(url$, "\n\r", i);
# If the token ends in a } it is a raster value or vector element.
if (right$(temp$, 1) == "}") {
arr[i - 1] = 1;
# If the last element was a URL, set add to false.
if (i != 1)
if (arr[i - 2] == 0)
add = false;
# If add is false, check if this point has the current raster value or is close
# to the current vector element.
if (!add) {
if (layer.Type == "Raster") {
if (rv[point.y, point.x] == StrToNum(GetToken(temp$, "{}", 1))) {
arr[i - 1] = 2;
add = true;
}
}
else {
element$ = GetToken(temp$, "{ }", 1);
table$ = GetToken(temp$, "{ }", 2);
field$ = GetToken(temp$, "{ }", 3);
value$ = "";
num = NumberTokens(temp$, "{ }");
for j = 4 to num
value$ = value$ + " " + GetToken(temp$, "{ }", j);
value$ = right$(value$, strlen(value$) - 1);
if (element$ == mode$) {
if (mode$ == "point") {
if (vv.point[elementNum].(table$).(field$)$ == value$) {
add = true;
arr[i - 1] = 2;
}
}
else if (mode$ == "node") {
if (vv.node[elementNum].(table$).(field$)$ == value$) {
add = true;
arr[i - 1] = 2;
}
}
else if (mode$ == "line") {
if (vv.line[elementNum].(table$).(field$)$ == value$) {
add = true;
arr[i - 1] = 2;
}
}
else {
if (vv.poly[elementNum].(table$).(field$)$ == value$) {
add = true;
arr[i - 1] = 2;
}
}
}
}
}
}
# Add the url to the list if add is true and it is not on the list.
else {
arr[i - 1] = 0;
if (add)
if (!list.ItemExists(temp$))
list.AddItem(temp$);
}
}
if (list.ItemCount == 0)
list.AddItem("No URLs found!");
cbRedraw();
# Destroy the status bar.
StatusContextDestroy(context);
StatusDialogDestroy(status);
# If the action is add, get URL from user.
if (action$ == "add") {
local class DATABASE db;
if (layer.Type == "Raster") {
item$ = PopupString(sprintf("Enter a URL to add for raster value %.2f:", rv[point.y, point.x]));
j = 1;
}
else {
if (mode$ == "point") {
db = OpenVectorPointDatabase(vv);
j = PopupSelectTableField(db, table$, field$);
value$ = vv.point[elementNum].(table$).(field$)$;
}
else if (mode$ == "node") {
db = OpenVectorPointDatabase(vv);
j = PopupSelectTableField(db, table$, field$);
value$ = vv.node[elementNum].(table$).(field$)$;
}
else if (mode$ == "line") {
db = OpenVectorLineDatabase(vv);
j = PopupSelectTableField(db, table$, field$);
value$ = vv.line[elementNum].(table$).(field$)$;
}
else {
db = OpenVectorPolyDatabase(vv);
j = PopupSelectTableField(db, table$, field$);
value$ = vv.poly[elementNum].(table$).(field$)$;
}
if (j > 0)
item$ = PopupString(sprintf("Enter a URL to add for:\n Table: %s\n Field: %s\n Value: %s",
table$, field$, value$));
}
# If there was no error getting table and field information, continue.
if (j > 0) {
# Read file into string.
url$ = "";
reffile = fopen(filepath$);
while(!feof(reffile)) {
temp$ = fgetline$(reffile);
if (temp$ == "")
temp$ = " ";
url$ = url$ + temp$ + "\n";
}
url$ = left$(url$, strlen(url$) - 1);
fclose(reffile);
# Add the URL to the appropriate location in the reference file.
if (list.GetItemAtPos(1) != "File not found!") {
temp$ = "";
for j = 1 to start {
temp2$ = GetToken(url$, "\n\r", j);
if (temp2$ == " ")
temp2$ = "";
temp$ = temp$ + temp2$ + "\n";
}
for j = 1 to numTok {
temp$ = temp$ + GetToken(url$, "\n\r", j + start) + "\n";
if (j > 1) {
if (arr[j - 1] == 2 and arr[j] == 0 and arr[j - 2] == 0)
break;
}
else if (arr[j - 1] == 2 and arr[j] == 0)
break;
}
if (j > numTok) {
j -= 1;
if (layer.Type == "Raster") {
temp$ = temp$ + "{" + NumToStr(rv[point.y, point.x]) + "}" + "\n";
}
else temp$ = temp$ + "{" + mode$ + " " + table$ + " " + field$ + " " + value$ + "}" + "\n";
}
temp$ = temp$ + item$ + "\n";
num = NumberTokens(url$, "\n\r");
for j = j + start + 1 to num {
temp2$ = GetToken(url$, "\n\r", j);
if (temp2$ == " ")
temp2$ = "";
temp$ = temp$ + temp2$ + "\n";
}
url$ = left$(temp$, strlen(temp$) - 1);
}
else {
if (layer.Type == "Raster") {
temp$ = "{" + NumToStr(rv[point.y, point.x]) + "}";
}
else temp$ = "{" + mode$ + " " + table$ + " " + field$ + " " + value$ + "}";
url$ = url$ + "\n\n" + layerName$ + "\n" + temp$ + "\n" + item$;
}
# This is currently the only way to to file modification other than overwriting data.
# Create a new file, write to it, and delete the old one.
RenameFile(filepath$, FileNameGetPath(filepath$) + FileNameGetName(filepath$) + ".old");
# Recreate file.
reffile = fopen(filepath$);
# Write to the new file.
fwritestring(reffile, url$);
# Close file.
fclose(reffile);
# Delete old file.
DeleteFile(FileNameGetPath(filepath$) + FileNameGetName(filepath$) + ".old");
}
}
}
else if (list.ItemCount == 0)
list.AddItem("No element found!");
list.VisibleItemCount = list.ItemCount;
if (list.VisibleItemCount > 10)
list.VisibleItemCount = 10;
}
else
list.AddItem("Type not supported!");
url$ = list.GetItemAtPos(1);
if (url$ != "No URLs found!" and url$ != "Type not supported!"
and url$ != "No element found!" and url$ != "File not found!")
list.SelectPos(1);
}
# Called the first time the tool is activated.
# If the tool implements a dialog it should be created (but not displayed) here.
func OnInitialize () {
WidgetAddCallback(Group.LayerSelectedCallback, cbLayer);
# Set up dialog
form = CreateFormDialog("Select a URL");
form.marginHeight = 2;
form.marginWidth = 2;
form.ResizePolicy = "RESIZE_ANY";
WidgetAddCallback(form.Shell.PopdownCallback, cbClose);
# Drawing area for displaying raster name.
da = CreateDrawingArea(form, 30, 350);
da.leftWidget = form;
da.topWidget = form;
da.rightWidget = form;
WidgetAddCallback(da.ExposeCallback, cbRedraw);
# List for displaying urls.
list = CreateScrolledList(form);
listParent = list.parent;
listParent.topWidget = da;
listParent.leftWidget = form;
listParent.rightWidget = form;
# Label for vector modes.
vectorLabel = CreateLabel(form, "Vector Mode:");
vectorLabel.topWidget = list;
vectorLabel.leftWidget = form;
vectorLabel.topOffset = 4;
# Form for toggle buttons for vector mode.
vectorModes = CreateRowColumn(form, 4);
vectorModes.topWidget = list;
vectorModes.leftWidget = vectorLabel;
vectorModes.rightWidget = form;
vectorModes.RadioBehavior = 1;
# Button to select points.
pointButton = CreateToggleButton(vectorModes, "Points");
WidgetAddCallback(pointButton.ValueChangedCallback, cbModeChanged);
# Button to select points.
nodeButton = CreateToggleButton(vectorModes, "Nodes");
WidgetAddCallback(nodeButton.ValueChangedCallback, cbModeChanged);
# Button to select points.
lineButton = CreateToggleButton(vectorModes, "Lines");
WidgetAddCallback(lineButton.ValueChangedCallback, cbModeChanged);
# Button to select points.
polyButton = CreateToggleButton(vectorModes, "Polygons");
WidgetAddCallback(polyButton.ValueChangedCallback, cbModeChanged);
# Separator between vector modes and actions.
line1 = CreateHorizontalSeparator(form);
line1.topWidget = vectorModes;
line1.leftWidget = form;
line1.rightWidget = form;
# Label for actions.
actionLabel = CreateLabel(form, "Action:");
actionLabel.topWidget = line1;
actionLabel.leftWidget = form;
actionLabel.topOffset = 4;
# Form for toggle buttons for options.
actions = CreateRowColumn(form, 3);
actions.topWidget = line1;
actions.leftWidget = actionLabel;
actions.rightWidget = form;
actions.RadioBehavior = 1;
# Button to select scan.
scanButton = CreateToggleButton(actions, "Scan");
WidgetAddCallback(scanButton.ValueChangedCallback, cbActionChanged);
# Button to select add.
addButton = CreateToggleButton(actions, "Add");
WidgetAddCallback(addButton.ValueChangedCallback, cbActionChanged);
# Separator between actions and command buttons.
line2 = CreateHorizontalSeparator(form);
line2.topWidget = actions;
line2.leftWidget = form;
line2.rightWidget = form;
# Button to open reference file.
openButton = CreatePushButtonItem("Open File...", cbOpen);
# Button to launch browser.
urlButton = CreatePushButtonItem("Launch Browser", cbGo);
# Button to close polyTool.
closeButton = CreatePushButtonItem("Close", cbClose);
# Row of buttons.
buttonRow = CreateButtonRow(form, openButton, urlButton, closeButton);
buttonRow.topWidget = line2;
buttonRow.leftWidget = form;
buttonRow.rightWidget = form;
# Add point tool.
pointTool = ViewCreatePointTool(View);
ToolAddCallback(pointTool.ActivateCallback, cbToolApply);
# Default file path.
filepath$ = _context.ScriptDir + "url.txt";
} # end of OnInitialize
# Called when tool is to be destroyed, will not be called if tool was never activated.
# If the tool implements a dialog it should be destroyed here.
func OnDestroy () {
cbClose();
DestroyGC(gc);
DestroyWidget(form);
} # end of OnDestroy
# Called when tool is activated.
# If the polyTool implements a dialog it should be "managed" (displayed) here.
func OnActivate () {
# Reset everything to default.
list.DeleteAllItems();
list.VisibleItemCount = 1;
pointButton.Set = 0;
nodeButton.Set = 0;
lineButton.Set = 0;
polyButton.Set = 1;
mode$ = "poly";
scanButton.Set = 1;
addButton.Set = 0;
action$ = "scan";
if (Group.ActiveLayer.Type == "Vector")
Group.ActiveLayer.UnhighlightAllElements();
DialogOpen(form);
pointTool.Managed = 1;
pointTool.HasPosition = 0;
# Find reference file
if (!fexists(filepath$))
cbOpen();
if (gc == 0)
gc = CreateGCForDrawingArea(da);
cbLayer();
setDefaultWhenClose = true;
} # end of OnActivate
# Called when tool is deactivated (usually when switching to another tool).
# If the tool implements a dialog it should be "unmanaged" (hidden) here.
func OnDeactivate () {
setDefaultWhenClose = false;
cbClose();
} # end of OnDeactivate