How to show all overridden attributes

VERY clever, @pat

If MySet is exposed in an Attribute Browser, then it would be a simple matter to apply the stamp to the suspect notes and read immediately in the AB those notes with local values.

1 Like

Yes, youā€™re quite right. Iā€™ll correct that.

Yep. And attribute browser can have query $MySet to show only notes with overridden key attributesā€¦

1 Like

Thanks a bunch Pat. Iā€™m a brand new user. Even if that doesnā€™t get me all the way there, itā€™s really instructive.

Further corrections to the logical Or and logical AND articles. Hopefully clearer. If not, do say! :grinning:

@pat

One thing worth mentioning is that I would never really worry about key attributes being overridden. In fact, I would expect them to be. Itā€™s the hidden ones that are problematic.

Hereā€™s the example that motivated my original post (topic 1 of this multi-topic thread):

I assigned a bunch of notes to the Task built-in prototype. Boy, that looked cool. I wondered what the little double sided arrow thing above the notes was, so I clicked on it. It rotated the note by 180. I didnā€™t like that so I clicked again to put it back. Little did I know (as a new user) that there now was an override in place. This means that if I were to alter the Task prototypeā€™s note direction, the one note I innocently played with would not conform. I can easily imagine a model, over a long period of time, collecting many instances of such cruft. Quite an insidious bug.

Such user mistakes were very common in my first few days of playing. All these mistakes applied to non-key attributes. If they had been key attributes, their assignment to a local value would have been completely obvious.

I do consider my behavior to be user error. However, if normal user behavior can be classified as user error, then some escape hatch is needed.

Thanks to all for this discussion. Obviously I was misunderstanding the |= operator, which I had always assumed to be a test for default value, rather than zero value. I guess the difference had not shown up in the (limited) uses to which I was putting it. Glad to understand it better.

1 Like

Just to be sure Iā€™m not missing somethingā€¦

The ā€œ|=ā€ topic has nothing to do with the topic I opened this thread for. It seems it is an assignment operator, not a querying one. Am I right?

Itā€™s not really an override (and it certainly isnā€™t a bug). I donā€™t note this by way of critique, but I think you may find it useful to read about Tinderboxā€™s inheritance model. That document refers to v6 but the logic is unchanged for v7.

The context was this: You were looking for a way to find non-default / over-ridden values. I mentioned |= as an operator that relied on a test of what I assumed were non-default values (but actually are non-zero values). So the point was: TBā€™s internal logic had a way of noting this distinction, which you could presumably rely on. That led to MarkA mentioning hasLocalValue(). Thatā€™s the sequence.

Thanks Mark. Iā€™m a software developer with lots of Javascript experience. Under the covers you can see that Javascript is in the mix of the Tinderbox program by reviewing the running threads. All the code syntax and paradigms are from Javascript, with some small liberties taken. Javascript developers would call a attribute value that differs from its prototypeā€™s (or superclass in traditional OO) an override. Youā€™re right, overrides are definitely not bugs.

When you debug Javascript in a web browser and inspect an object, you see just the attributes defined directly on that object. You have to navigate up the prototype chain to see further attributes. The view of the single object and its attributes is what Iā€™m looking for. Iā€™m no longer looking for a solution in the Tinderbox program itself because Iā€™m pretty certain this thread would have mentioned it by now. Patā€™s answer involving $KeyAttributes was close to an answer to my question.

Itā€™s interesting that this thread started focusing on the ā€œ|=ā€ operator. The focus was the result of a lack of clarity on the topic rather than its applicability to the original question. This thread was incredibly valuable in that it added that needed clarity. Particularly interesting is that in Javascript ā€œ|=ā€ means something different. That would have thrown me had I encountered ā€œ|=ā€ without have seen this thread first.

Itā€™s pretty clear to me that my concern of accidentally introducing unintentional overrides is not shared by others. Iā€™ll write my own solution as a simple command line program and just keep it for personal use.

Threw me off a bit too ā€“ I wasnā€™t expecting |= to have the meaning it seems to have in Tinderland. :slight_smile:

Actually, I would say youā€™ve introduced an important case that may be an outlier of sorts, but nevertheless valid ā€“ and I would hazard that it has bedeviled others who didnā€™t have your background and were unable to describe what was going on. So, if you confect a solution, Iā€™d encourage you to share it here. If for nothing else, then for posterity and completeness, but also because it might be useful to others who donā€™t yet know they need a solution. :laughing:

Actually, Javascript is not involved at all with Tinderbox action code.

I think those threads are associated with the HTML Preview pane.

Both Javascript and Tinderbox are influenced by SELF, the original experiment in prototype inheritance. And both inherit a lot of syntax from C.

I remember self. I had a friend who had a friend who was one of its developers. Thatā€™s my only claim to fame.

Thanks for the sentiment Paul. I appreciate it.

OK, I wrote it - well good enough for me and for now. Itā€™s a one page Java program. Itā€™s a bit embarrassing and hackish (no false modesty). Itā€™s probably 50% bugs. Iā€™ll post it below for completeness and closure.

If anyone at all wants more information Iā€™d be happy to discuss. But, if this merits any real interest, then the true home for this functionality is in Tinderbox itself.

The program has the snippet

private enum Uninteresting {
	IsComposite, MapScrollX, MapScrollY, Modified, SelectionCount, Xpos, Ypos, Created, Text;
}

which I expect to grow a lot. These attributes are not included in the output of the program. The interesting thing is that I noticed some attributes that I had to investigate which ended up in the uninteresting list. But just that exercise was a learning opportunity. The biggest challenge for me with Tinderbox is learning all the attributes. Also, I expect to learn something new about Tinderbox every time my program crashes. (wishful thinking)

Iā€™ll run the program now and again as I use and learn Tinderbox. Iā€™ll just turn it into a ā€œjarā€ and sit it alongside a little shell script

#!/bin/sh
# Tinderbox attribute dump
java -jar `dirname $0`/tb.jar $1

to run it.

So, here it is. Itā€™s completely uncommented because it will be obvious or impossible to understand, depending on your background.

package tb;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Assigns {

	private enum Uninteresting {
		IsComposite, MapScrollX, MapScrollY, Modified, SelectionCount, Xpos, Ypos, Created, Text;
	}

	private static List<String> ignoreSet = Arrays.stream(Uninteresting.values()).map((value) -> value.name())
			.collect(Collectors.toList());

	public static void main(String[] args) throws Exception {
		String pathStr = args[0];
		new Assigns().report(pathStr);
	}

	private void report(String pathStr) throws Exception {
		Path file = Paths.get(pathStr);
		List<Item> items = itemsFrom(documentFor(file));
		List<Note> notes = items.stream().map((item) -> noteFrom(item)).collect(Collectors.toList());
		notes.stream().forEach((note) -> {
			System.out.println(note.name);
			note.attributes.stream().forEach((attribute) -> {
				System.out.println("  " + attribute.name + " : " + attribute.value);
			});
		});
	}

	private Note noteFrom(Item item) {
		Note note = new Note();
		item.attrs.stream()
		.filter((attr) -> !ignoreSet.contains(attr.getAttribute("name")))
		.map((attr) -> {
			Attribute attribute = new Attribute();
			attribute.name = attr.getAttribute("name");
			Node child = attr.getFirstChild();
			attribute.value = child != null && child.getNodeType() == Node.TEXT_NODE ? child.getNodeValue() : null;
			return attribute;
		}).forEach((attribute) -> note.accept(attribute));
		return note;
	}

	private List<Item> itemsFrom(Document doc) {
		List<Item> items = new ArrayList<>();
		NodeList nodeList = doc.getElementsByTagName("item");
		for (int i = 0; i < nodeList.getLength(); i++) {
			Element itemElement = (Element) nodeList.item(i);
			Item item = new Item();
			items.add(item);
			NodeList children = itemElement.getChildNodes();
			for (int j = 0; j < children.getLength(); j++) {
				Node child = children.item(j);
				if (child instanceof Element) {
					Element attr = (Element) child;
					if (attr.getTagName().equals("attribute")) {
						item.attrs.add(attr);
					}
				}
			}
		}
		return items;
	}

	private Document documentFor(Path file) throws Exception {
		DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = null;
		builder = builderFactory.newDocumentBuilder();
		return builder.parse(file.toFile());
	}

	private static class Note {
		private String name;
		private List<Attribute> attributes = new ArrayList<>();
		private void accept(Attribute attribute) {
			if ("Name".equals(attribute.name)) {
				name = attribute.value;
			} else {
				attributes.add(attribute);
			}
		}
	}

	private static class Attribute {
		private String name;
		private String value;

	}

	private static class Item {
		private List<Element> attrs = new ArrayList<>();
	}

}
1 Like

Iā€™ve been pondering on this too. Iā€™ve been trying to think of a way to do a visual lexicon of the attributes relating to the UI (i.e. how notes look). But itā€™s very complex, not least because the same attribute can have a different effect in a different context. Trivial example: $Color is the colour of a note icon on a map but in all other views is the colour of the font used to draw that item. Fine if you know, sort of hard to categorise otherwise short of exhaustively documenting each view.

However, I do think aTbRef (or some other ref) needs a sort of visual look-up now there are >300 system attributes. Perhaps just a series of annotated screen grabs, e.g.

In a map, even a basic a non-container note has c.57 possible visual/functional customisations (and thatā€™s without composite functions). These attributes are mainly in the Map group of System attributes but also in General and others. Some of these can be reviewed/set in the Inspector but not all and some, e.g. $Pattern, effectively split between a pop-up selection (simple patterns) and needing Quickstamp (calculated patterns). Iā€™m not criticising the Inspector here but simply pondering how to make the range of (accidentally) alterable things more easily investigated.

The inspector does deserve constructive criticism. The person who wrote it does not. Priorities and circumstance are major contributors to all code.

Tinderbox is an amazing program. I bought it as an experiment; now Iā€™m hooked. Only as I learn it do I appreciate its value. The hurdle to learn it is part of the hurdle to its adoption. Iā€™ve tried Tinderbox in the past and decided against buying it since I thought it would take too much time to learn. The documentation included with Tinderbox is great. But, what seems to be missing is contextual help.

The attributes and their meanings is a big hurdle to me because there are so many. The inspector is the main tool used to get at those attributes. The inspector offers little assistance in understanding those attributes. A hover with some text explaining the selected attribute would be an enormous help. A category in the attribute browser showing a summary of attribute assignments ordered by the prototype chain would be an enormous help. (That last is really the topic of the OP.)

Tinderbox doesnā€™t stand by itself. Its significant other is TbRef. This thread was introduced about functionality in Tinderbox. Most of the posts on this thread are about or mention TbRef. TbRef is tacitly an official part of Tinderbox.

If thatā€™s acknowledged, then a good step would be to include links to TbRef directly on the attributes in the attribute browser. That landing page inside TbRef would be the gateway to exploring that attribute and closely related ones. The alphabetical listing in the attribute browser (albeit categorized) does not represent those relationships.

Itā€™s a very bold post for a brand new user.

1 Like

Thatā€™s not quite trueā€¦ Iā€™ve done the exact thing you mention, on multiple occasions. I notice that one note is behaving strangely, and after some investigation discover that it has an overridden attribute rather than an inherited attribute.

I agree that it would be nice to have a single list of overridden attributes ā€“ you can send a feature request to info@eastgate.com

I guess itā€™s worth pointing out, as I do occasionally for the benefit of newer users, that aTbRef is a resource written/hosted by me, Mark Anderson and which I share with the Tinderbox community via its HTML version. Iā€™ve been using Tinderbox since c.2004 and after originally volunteering as a ā€˜wiki gardenerā€™ for the Tinderbox wiki Iā€™ve since become essentially the lead community support for Tinderbox. I currently moderate this forum and the Backstage one. Iā€™m also a beta tester (primarily Tinderbox but Storyspace also). Although I liaise closely with Eastgate I am (for disclosure) an unpaid volunteer so have no formal ties to the appā€™s publisher.

aTbRef as a TBX doc grew out of my own attempts to get to grips with all facets of the app. As I was also trying to work out HTML export at the time, making a web version seemed a good exercise. I generally use aTbRef in its web form and besides the current v7.0 baseline I also keep online older versions based on v2.3.4, v4.5, v4.6, v5 and v6. If aTbRef is linked to a lot in the forums, it is because we can; it would be much harder trying to refer to a page in the Help manual instead - not the the manual is lacking in content. The appā€™s Help men also gives access to two useful PDFs bundled in the app (ā€˜Getting Started with Tinderboxā€™ and ā€˜Actions and Dashboardsā€™).

aTbRef is, by intent, not a how-to but a general reference to what all the UI and code features actually. As it happens the short sentence describing an attribute.

Any errors/omissions in aTbRef are mine (errors reports always welcome). Enjoy. :grinning:

1 Like

Your efforts are much appreciated. I donā€™t think I would have followed through with my purchase if aTbRef hadnā€™t existed. The task of figuring things out (all the things you did) would have been daunting.

3 Likes