URLS.SML

  Download

More scripts: Display Toolbar

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