How to control which GTK widgets visible in an expanded row of a tree? - treeview

I'm building a tree store with GTK3 in C in which there are primary rows that are always displayed, and by clicking on the little triangle icon to the left of a primary row, additional secondary (child) rows expand below the primary. As an example, consider that the primary rows could be directories, and when they're expanded, rows below that show the files in those directories. I'm doing this to allow a user to select primary items to be deleted, while the secondary rows are just informational, telling, for example, what files are in the directory, so they'll know if they really want to delete the whole thing.
To enable selection for deletion, the first column contains a GTK_CELL_RENDERER_TOGGLE, and I have a callback associated with the checkbox toggle. Everything works nicely except for one thing. When the user clicks the little triangle item to expand a row, most of the content of the primary row does not appear in the secondary rows (this is expected and desired), but... the checkbox toggle does appear in the first column. Although in a directories/files example that might be meaningful, in my case it makes no sense to think of deleting the content of the secondary rows.
When building the secondary rows, I've tried things like just:
gtk_tree_store_set(TS,&J,2,"filename",-1);
or
gtk_tree_store_set(TS,&J,0,NULL,2,"filename",-1);
hoping that NULL would cause the toggle to be suppressed, but to no avail. GTK still displays a checkbox, probably just interpreting the NULL as a zero.
Is there a way to control (and in my case, suppress) display of the toggle? Or more generally, is there a clean way to control which columns are displayed in child rows? It seems to work with TEXT, but just not with TOGGLE.
A little later: There is a potentially useful function called gtk_cell_renderer_set_visible(), but it requires a reference to the cell renderer. How to acquire that on a per-row or per-cell basis when all I have during construction is the GtkTreeStore and a GtkTreeIter?

There are (at least) 2 solutions:
Base class GtkCellRenderer has visible property. You can add extra field to your model which indicates, whether Toggle should be visible for this row.
If there are other fields in you model which indicate whether it's a primary or secondary row but not directly you can use gtk_tree_view_column_set_cell_data_func to set a function to be called before rendering. There you can call gtk_cell_renderer_set_visible or any other function to set renderer's properties manually.

Related

How to deal with recycling lists

I'm building a UI test suite for an iOS app using XCUITest api. The app uses recycle lists and I need to access specific cells of those lists during my tests as shown in the code below:
let cells: XCUIElementQuery = app.descendants(matching: XCUIElement.ElementType.any).matching(identifier: "cells_accessibility_id")
let cell: XCUIElement = cells.element(boundBy: index)
cell.tap()
My problem is that since this is a recycle list, as soon it scrolls by any reason during the test (like animations), cells are unloaded, "cells" won't return all items and then "index" won't get the right cell from the list or becomes out of bounds.
Is there another way that I can retrieve the whole list regardless of element visibility? Or do I have to change my tests/try another approach?
You can not rely on the indices of reusable cells as you pointed out, however there is usually a way to eliminate the dependency on having to test cells at certain indices. The solution will depend on what you want to test, but here are some possible alternative strategies:
If your table cells are always the same, you could give them each a hard-coded identifier based on their contents.
If your table cells have dynamic content in them, you could use stub test data for each test to make it so that there is only one cell on screen (the one which is relevant to the test).
If you can identify the cell you want by the views contained within the cell, you can search each cell for the relevant views before selecting it, instead of relying on its index.

IAccessible deisgn questions: child objects, thread safety, and header rows/comctl32.dll header controls, and a few other questions on top of that

So before I continue developing my accessible table I read this, on exposing data tables and the general MSAA documentation and I want to clear up a few things before I actually go ahead and write out this implementation, just so I can get everything just right.
For the record, this table is strictly owner-data and is row-based, where a given row can be selected, and a single cell within this row can be focused. Otherwise it behaves similarly to a listview control, but is not one, so I'm not going to try to take advantage of its accessibility features. In particular, any column can contain text, images, or checkboxes (and I might add more features); there might be background colors and text editability in the future as well. All cells in a given column have one of these types. The type will not change during runtime.
I am choosing to use MSAA because I still need Windows XP support, and I would rather not require developers and end users to have both SP3 and the .net framework together, which UI Automation seems to require (and even if the SP3 part is wrong, the "is not standalone/does not come out of the box with the OS" part still makes me uneasy about implementing that).
Is it process-safe/thread-safe to call my internal control functions within the accessible object method implementations, or should I use WM_USER messages to make sure everything happens all on one thread of one process? (In addition, would my error handling/debugging traps be run in the client or in the server in either case?)
From what I can gather, I need to build a three-level IAccessible hierarchy: the table itself on top, followed by each row, followed by each cell in the row. However, the various IAccessible methods that take a child object only take a VT_I4 VARIANT to specify the child. Does this mean I'm going to have to create an IAccessible for each row as well, or for each cell as well, or something else? Should I have a standard accessible object for each of these? Can they share? And what about NotifyWinEvent(); how would I indicate that a given cell has changed? Or should I say the whole row has changed...?
If the answer to question 2 is "yes", I'm going to wind up with a lot of IAccessible objects that need to be notified when the table control is destroyed. If the answer to question 1 is "it is not thread-safe", then is it safe to hold a lock in my IAccessible methods whenever I access my table control and have that hold the lock when it's time to invalidate all those IAccessibles? Or should I investigate some other approach? I see talk on MSDN of "proxy objects" but I'm not really following how that would help... especially if I need to make lots of IAccessibles.
From what I can gather I need to return (number of rows) + 1 rows in my table's get_accChildCount() method, with the first row being full of column header cells. But I'm not using a custom header control; I'm using the standard comctl32.dll header control. Should I hide that control and construct my column headers according to the Exposing Data Tables document or should I relegate the first row to the header control? I don't see a way to do both... (I do not have row headers, so will not be implementing that.) Columns can be user-resized, but may be automatically sized to fit until the user first does so (maybe).
Is it safe to relegate IDispatch methods to the window handle's standard accessible object? Even in the case of the row and cell IAccessibles? Or will the standard accessible object's IDispatch not call my IAccessible methods?
What should accDoDefaultAction() do for a checkbox cell, toggle the checkbox state? And for an editable text cell, should it enter editing mode?
Thanks. (Hoping none of this sounds dumb...)
UPDATE 6 January 2015
I changed the wording of some of the paragraphs above and have one more question:
How do I correctly check for errors from LresultFromObject(), by casting to an HRESULT and checking that, or by comparing a signed version of the LRESULT value and seeing if it's less than zero, or something else?

Does anyone know why an object would miss a property?

We have a script that export our Indesign documents to HTML and one of the routine is to export tables. In this script we go throught each Tables->Rows->Cells and evaluate some of the properties (i.e. bottomEdgeStrokeType, topEdgeStrokeType, etc...) and transport them to HTML.
Now yesterday we had problem converting one particular document because some cells were missing the "bottomEdgeStrokeType" property entirely. I've discovered this by outputting the properties of each cells and compare the faulty ones with the others.
This line bellow was trowing the error: "Invalid object for this request.".
var cellType = cell["bottomEdgeStrokeType"];
Now, to fix this I've wrapped this around a try catch block to handle the case when it's not there, but now what is puzzling me is how on earth can Extendscript instantiate an object with missing properties?
Indesign version: CS5.5
A property is not only 'undefined' if it cannot exist at all (such as asking for the parent text frame for a character in overset text), but InDesign's Javascript engine also fails to return a reasonably accurate result for multiple values.
If you ask for "the" point size of a paragraph, where this paragraph contains multiple sizes, poor ID does not consider to return something like CONSTANT.Mixed, or the first value only, or (what I might have preferred) an array of the values; it returns undefined instead.
So how can a single table cell have multiple bottom strokes? If the cell underneath it is split into multiple cells, and one has a "top" stroke but the other has not.
It's difficult to recommend an adequate solution. You could first test if the current cell is "merged" (as far as InDesign's internal table model is concerned) with columnSpan; and if so, iterate over the number of columns spanned and test the next row's cells for their top stroke, which in theory should match the bottom stroke of the cell above. (I find myself wondering if this is always true. ID's table model is ... weird. It's not entirely like a HTML table, despite the functional overlaps.)
If columnSpan is greater than 1 and equal to the number of cells immediately below the current one, you could test if all of their "top" values are the same and if so use that value. (I never tested this so ID's table model may simply fail because a cell is merged, regardless of same-values or not.)
One could attempt to flag this cell's next row to output "top" strokes as well -- but alternating top and bottom strokes may not align nicely in CSS, side to side. Perhaps it's best to translate only the first top stroke value to "the" bottom stroke property for your current cell, and fix up manually where needed (how?) or, a reasonable action, hope that no-one will ever notice it.

List Control Adds a Space for an Image to Column 0 When Subsequent Columns Have Images

I’ve come across a problem with Windows list controls (I am specifically using MFC, but it looks like it applies to all list controls in the Windows common controls library).
In my specific case, I want to create a list control that has two or more columns. The first column (0) is text-only and is used to allow the user to jump to entries by typing the text in that row. Column two (or three, or four, or whatever) has an image (or an image and text; either way).
This much is all well and good and can be done easily without problem, however the final list control then ends up having a space to the left of the text in column 0 (it may be on the right on an RTL system). This spacer appears to be reserved for an image and I cannot figure out a way to prevent it. (Arranging the specific order of the columns did not change anything.)
Looking around, I found some other people complaining of the same thing, specifically this thread which leads to this thread. The proposed solution does not work because as was stated, simply shrinking the width of column zero merely cuts off the text rather than the image spacer (plus, you then have to prevent and/or process any changes to column widths that the user tries to make).
Does anyone have any ideas of how to fix this bug short of writing a list control from scratch or using one of the too-fancy grid controls on CodeProject/CodeGuru/etc.?
Thanks a lot.
Did you try to change the iIndent member of the LVITEM struct? MSDN says this:
iIndent Version 4.70. Number of image widths to indent the item. A
single indentation equals the width of
an item image. Therefore, the value 1
indents the item by the width of one
image, the value 2 indents by two
images, and so on. Note that this
field is supported only for items.
Attempting to set subitem indentation
will cause the calling function to
fail.
Column 0 is special in a ListView. As soon as you assign a small image list to the ListView, the control expects you to show an image in column 0, so it leaves space for it.
Solutions:
make column 0 zero-width, give it the value you want the user to be able to type. Column 1 becomes your "first" text column. Columns 2+ are for your images. You need full row select style for this to work. Yes, you have to prevent the user from resizing column 0. Yes, that is a pain.
make a column that does have an image to be column 0 and use LVM_SETCOLUMNORDERARRAY to rearrange the display order
owner draw the items.
give column 0 an icon (just to cover all bases)

What are ways to reduce the number of columns in a table/grid?

I have a datagrid with many columns. This makes it pretty wide. Now we want to add more information to the table. Aside from removing or shortening existing columns what are some ways we might be able to add additional information without adding new columnes.
The data we want to add would be one of several values. For example:
Projected
Actual
Other
For other cases when the value was an off/on or true/false we would change the color of the row. In this case that doesn't seem to be a good option.
Another thing we considered is using an icon to indicate the information.
Any other ways this could be done?
A solution i've seen implemented with grid components is to have a column chooser - some sort of popup dialog that lists the columns and you can select which ones you would like to see in the grid. You should be able to invoke this popup by triggering it from the grid, e.g. it might appear as an option when the user right clicks and causes the context menu to appear.
Can you group related information into tabs?
an overflow area? ie a number of fields underneath the table that populate based on the selected row.
or just only show the minimum needed info and the have full details in a popup when doble clicked or something..
1) Popup on row hover
2) Drop open inline in the grid with extra info on row click
One technique I've used in the past was to create a "container" type of class that has its own labels and textboxes, and you can arrange them however you want, then insert this class into a single grid column. You still have to do some tricks on binding multiple controls that are not native "grid column" controls, but should help you along. Then, you can actually have each row a single container control in a single grid column...
You can't add completely new data to a grid without reserving a column to display it. The best solution I've seen is to provide only the essential information in the grid displaying all records, and then create a drilldown view that shows all of the data for one row. The drilldown can either be a new view in the same form, a popup for an additional window, or perhaps a mouseover popup.
I've worked on systems that use all sorts of shortcuts to display every last bit of information on a single page, and I found that it just made everything more confusing and harder to use. "Oh, that little icon there means that <insert something totally unrelated to the icon picture>."

Resources