Is it possible to instruct a `Gtk::TreeView` to display a custom type? - c++11

There is something I don't understand how to do with Gtkmm 3.
I have a custom business type that I have declared like this:
enum class Eurocents : int {};
I would like to render this type into a Gtk::TreeView which has a Gtk::ListStore as model. So I declare a Gtk::TreeModelColumn<Eurocents>, and add it to the model. I then append_column this model column to the Gtk::TreeView with an appropriate title.
I then append_row to the model and set the value corresponding to the column to (Eurocents)100.
The result I get is that the cell is displayed empty. Understandably so, because I would not expect Gtkmm to know how to render my arbitrary type.
I would like to instruct Gtkmm on how to render my type.
I already know how to display Glib types like Glib::ustring and formatting to Glib::ustring for display is possible, but it is not the subject of the question.
Is it possible to code columns that can display arbitrary types like this? And if so, how? What is required for sorting to work?

The most common, and easiest way, is to use a cell_data_func callback. For instance, you can create your own instance of a Gtk::TreeView::Column (the view column), pack a cell renderer (or more) into your Gtk::TreeView::Column, append your Gtk::TreeView::Column to the TreeView with Gtk::TreeView::append_column(), and call set_cell_data_func() on your Gtk::TreeView::Column():
https://developer.gnome.org/gtkmm/stable/classGtk_1_1TreeViewColumn.html#a3469e1adf42e5932ea123ec33e4ce4e1
You callback would then get the value(s) from the model and set the appropriate values of the properties of the renderer(s).
Here is an example that shows the use of set_cell_data_func(), as well as showing other stuff:
https://developer.gnome.org/gtkmm-tutorial/stable/sec-treeview-examples.html.en#sec-editable-cells-example
This link should also be useful:
https://developer.gnome.org/gtkmm-tutorial/stable/sec-treeview.html.en#treeview-cellrenderer-details
If you like, Gtk::TreeView::insert_column_with_data_func() makes this a little more concise: https://developer.gnome.org/gtkmm/stable/classGtk_1_1TreeView.html#a595dcc0b503a7c1004c296b82c51ac54
As for the sorting, you should be able to just call set_sort_func() to specify how the column is sorted: https://developer.gnome.org/gtkmm/stable/classGtk_1_1TreeSortable.html#a3a6454bd0a285324c71edb73e403cb1c
Then this regular sorting advice should apply: https://developer.gnome.org/gtkmm-tutorial/stable/sec-treeview-sort.html.en

Related

Apply a sort to a dataset in a PowerApps component (PCF)

I’m trying to create a new dataset type Powerapps Component (PCF). For the moment I am using it to display a view of the records that are available in an entity in Microsoft Dynamics CRM.
I wish to make the view sort itself when I click on the grid column headers (in a similar way that the default CRM grid view does). I'm trying to figure out how to apply a sort to the dataset so that I can refresh it as indicated by the documentation for the dataset.refresh() function:
Refreshes the dataset based on filters, sorting, linking, new column.
New data will be pushed to control in another 'updateView' cycle.
The dataset object does have a “sorting” property, but changing its value and then refreshing the dataset doesn’t seem to have any effect. After the refresh, the sorting property reverts to the value it had before I changed it.
In short, the click handler for the grid header does something like the following bit of code. The refresh gets done and my updateView() function gets called as expected but the sorting was not applied.
dataset.sorting = [{name: 'createdon', sortDirection: 1}];
dataset.refresh();
Any help on getting the dataset sorting to work would be appreciated.
I've been experimenting with PowerApps Component Framework a little bit recently and I can confirm that the following code won't be working:
dataSet.sorting = [ { name: "columnName", sortDirection: 0 } ];
However, I managed to get this one working for me:
dataSet.sorting.pop(); // you may want to clean up the whole collection
dataSet.sorting.push({ name: "columnName", sortDirection: 0 });
I haven't really figured out the reason of this behavior. The sorting array may be implemented as some form of observable collection in the background.
I hope this will guide you to a functioning solution.
The documentation is pretty abysmal here, but here is my best guess from putting a few different pieces of information together.
TLDR: I think there is some kind of extra method that needs to be called on the .sorting property, but I can't find out what it is called. Maybe something like:
dataset.sorting.setSorting({name: 'createdon', sortDirection: 1});
I think you're going to have to try a bunch of likely method names and see what works.
Background and links:
The only reference I could find to dataset.sorting was from here:
In this preview for canvas apps, only a limited set of filtering and sortStatus methods are supported. Filter and sort can be applied to dataset on primary type columns except for the GUID. Filter and sorting can be applied in the same way as in model-driven apps.To retrieve the dataset with filtering and sorting information, call
the methods in context.parameters.[dataset_property_name].filtering
and context.parameters.[dataset_property_name].sorting, then invoke
the context.parameters.[dataset_property_name].refresh().
So it seems that the .filtering and .sorting properties are handled similarly, and that there are some methods attached to them, and only some are supported. That is about as vague as they could make it...
I did find an example of how .filtering is used:
_context.parameters.sampleDataset.filtering.setFilter({
conditions: conditionArray,
filterOperator: 1, // Or
});
There is a brief reference to .setFilter() in the docs, as well as FilterExpression
There is a SortStatus reference, but it doesn't have any corresponding methods explicitly called out. It is possible that this is not yet a supported feature in the public preview, or the documentation is lacking and the name and syntax of the method you need to call on .sorting is not yet documented.

Can we dynamically set the value of "list" attribute of <apex:relatedList> component?

I am trying to design a generalized detail page for an object.
In the controller class I find the list of all child relations of that object.
I then want to create for each child relations found and for accomplishing this I will have to dynamically set the value of list attribute within it.
For example :
<apex:relatedList subject={!ObjName} list="{!relatedListName}" />
But the problem here is that list attribute only accepts String literal, so can't implement it. Please suggest a way for this requirement to be accomplished.
Yes, you can dynamically set the value of the "list" attribute on a relatedlist tag, and you do so via Dynamic Visualforce. This question has since been asked and concisely answered here on the Salesforce Stack exchange for any future browsers:
https://salesforce.stackexchange.com/questions/7531/apexrelatedlist-list-dontexistinallorgs-c-only-solveable-with-dynamic
Here is the general solution:
In a custom controller, add a function to dynamically generate the RelatedList markup. I will assume from your wording that you have already accessed the full list of child relationships in your controller, so in order to spit out all the lists in one block, I would use something like this:
public Component.Apex.OutputPanel getDynamicList()
{
Component.Apex.OutputPanel outPanel = new Component.Apex.OutputPanel();
for(String id : childNames) {
Component.Apex.RelatedList relList = new Component.Apex.RelatedList();
relList.list = id;
outPanel.childComponents.add(relList);
}
return outPanel;
}
In the middle there, you can dynamically set any string to the "List" value, and by iterating through your list of strings, you are adding related list objects over and over again. (To simply add one list, remove the for loop, and make the "id" string value whatever specific relationship you wish to display).
Then on your visualforce page, you can render this block out using a dynamic visualforce tag:
<apex:dynamicComponent componentValue="{!DynamicList}" />
(as you may know, the formulaic value field will dig up the getter automatically)
Great success!
I would suggest trying apex:dataTable or apex:repeat to build your own list display. You will likely need a wrapper class to handle passing attributes and values from the sObject to the page.

Extend a Varien Form Element for a Custom Module

Improving on this question:
Is it good practice to add own file in lib/Varien/Data/Form/Element folder
The accepted answer shows how to extend a Varien form element, but this will not work if you want to package it into a custom module.
What would be the proper method of extending the Varien form element in a module? A simple XML setting I'm hoping?
Update:
Thanks Vinai for the response. Although that does work, I was hoping to extend the form element somehow. My extension is using the base File form element to allow administrators to upload files to categories. So, I'm not directly adding the form elements to the fieldset myself.
I suppose it's possible to to check for the file input on my category block on the backend: Mage_Adminhtml_Block_Catalog_Category_Tab_Attributes , and then change the form element if it is 'file' to 'mycompany_file' -- but this seems like a workaround.
Is there an easier way? Thanks again Vinai.
On the Varien_Data_Form instance you can specify custom element types like this:
$fieldset->addType('custom', 'Your_Module_Model_Form_Element_Custom');
Then, add your element with
$fieldset->addField('the_name', 'custom', $optionsArray);
If you are using a form without fieldsets you can do the same on the Varien_Data_Forminstance, too.
EDIT: Expand answer because of new additional details in the question.
In the class Mage_Adminhtml_Block_Widget_Form::_setFieldset() there is the following code:
$rendererClass = $attribute->getFrontend()->getInputRendererClass();
if (!empty($rendererClass)) {
$fieldType = $inputType . '_' . $attribute->getAttributeCode();
$fieldset->addType($fieldType, $rendererClass);
}
Because of this the attribute frontend_input_renderer on the attributes can be used to specify custom element classes.
This property can be found in the table catalog_eav_attribute, and luckily enough it isn't set for any of the category image attributes.
Given this, there are several ways to apply customizaton.
One option is to simply set the element class in the table using an upgrade script.
Another would be using an observer for the eav_entity_attribute_load_after event and setting the input renderer on the fly if the entity_type_id and the input type matches.
So it is a little more involved then just regular class rewrites in Magento, but it is quite possible.
You don't necessarily need to have a file in the lib/Varien/ directory in order to extend it. If you needed to add an element to that collection, you should be able to extend one of the Elements in your app/code/local module. The answer to the question you referenced seems to also indicate this is the case. I would create your custom field, extending its highest-level function set (i.e., lib/Varien/Data/Form/Element/File.php).
If you want to override the Mage_Adminhtml_Block_Catalog_Category_Tab_Attributes block, then you should extend that block in your module and then reference the new one. You may wish to extend the block using an event observer rather than an XML rewrite, for compatibility purposes.

Qt: Using default model for selecting my data

I am quite new to Qt and am in a situation where I want to use a model for my needs:
I have a dynamic number of instances of a subclass that need to be handled differently (different UI controls for each if it is selected). I want to get a list view where I can add new elements or delete old ones, as well as disabling/enabling existing ones.
Of course I want to rewrite as least of the code as possible, so I thought of utilizing the Listwidget and a ListModel to give some controls to the user. But how to link these (or better the items) to instances of the classes?
Do you know any tutorials on this?
I already looked in QtDemo and Google but I do not know the right words to search for
so I had no good results.
Basically what I think I need is a model item that accepts Collider* for its data.
But when I plug this into QStandardItem.setData() it says error: ‘QVariant::QVariant(void*)’ is private
So I found the solution to this problem.
As QStandardItems are capable of storing QVariants as data I wanted to store a pointer to my data in a QVariant. To achieve this I had to use Q_DECLARE_METATYPE(MyType*).
With this I was able to
MyType *MyInstance = new MyType;
QVariant data;
data.setValue(MyInstance);
QStandardItem *item = new QStandardItem("My Item");
item->setData(data);
standardModel->appendRow(item);
And the best is you can add as many types you want and let QVariant do the work to decide if it contains the type you wanted:
if(v.canConvert<MyType*>())
//Yes it is MyType
else if( v.canConvert<MyOtherType*>())
//Oh it is the other one
So finally this only requires to declare the meta type so you do not have to subclass any items.
Also you should read on the limitations of this here:
Q_DECLARE_METATYPE
qRegisterMetaType
Does this page answer your questions? There's an example of deriving a StringListModel item that you might be able to use as a template

Duplicated Zend_Form Element ID in a page with various forms

How do I tell the Zend_Form that I want an element (and it's ID-label, etc) to use another ID value instead of the element's name?
I have several forms in a page. Some of them have repeated names. So as Zend_Form creates elements' IDs using names I end up with multiple elements with the same ID, which makes my (X)HTML document invalid.
What is the best solution to fix this, given that I really have to stick with using the same element names (they are a hash common to all forms and using the Zend_Form Hash Element is really out of question)?
Zend_Form_Element has a method called setAttribs that takes an array. You may be able to do something like $element->setAttribs(array('id' => "some_id"));
or you can do $element->setAttrib('id', 'some_id');
Thanks, Chris Gutierrez.
However, as I said, I needed to get ride of the default decorator generated IDs like -label. Wiht the $element->setAttribs() it is not possible, however.
So based on http://framework.zend.com/issues/browse/ZF-7125 I just did the following:
$element->clearDecorators();
$element->setAttrib('id', 'some_id');
$element->addDecorator("ViewHelper");
Whoever sees this: please note this was enough for what I needed. But may not be for you (the default settings has more than the viewHelper decorator).

Resources