Glade/gtkmm TreeView - c++

In following up with an answer to my previous question on this issue, I've made some progress and am looking for the next bit of guidance. In brief, I'm having trouble loading up a Treeview from Glade with a gtkmm application.
To start, here's the source. The class:
typedef struct
{
Gtk::Window *window_info;
Gtk::TreeView *treeview_info;
Glib::RefPtr<Gtk::ListStore> liststore_info;
class InfoColumns : public Gtk::TreeModel::ColumnRecord
{
public:
InfoColumns() { add(time); add(message); }
Gtk::TreeModelColumn<string> time;
Gtk::TreeModelColumn<string> message;
} info_columns;
}UiElements;
class GuiManager
{
Glib::RefPtr<Gtk::Builder> builder;
UiElements elements;
public:
GuiManager();
void info_handler(string msg);
};
The definition:
GuiManager::GuiManager()
{
builder = Gtk::Builder::create();
builder->add_from_file("GUI3.glade");
builder->get_widget("window_info", elements.window_info);
builder->get_widget("treeview_info", elements.treeview_info);
//these two methods of loading the liststore appear to function identically
elements.liststore_info = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(builder->get_object("liststore_info"));
// elements.liststore_info = Gtk::ListStore::create(elements.info_columns);
elements.treeview_info->set_model(elements.liststore_info);
//if I append the columns, the data appears at the end of the list
// elements.treeview_info->append_column("Time", elements.info_columns.time);
// elements.treeview_info->append_column("Message", elements.info_columns.message);
}
void GuiManager::info_handler(string msg)
{
Gtk::TreeModel::Row row = *(elements.liststore_info->append());
row[elements.info_columns.time] = "Now";
row[elements.info_columns.message] = msg;
}
And the XML:
<object class="GtkListStore" id="liststore_info">
<columns>
<!-- column-name Time -->
<column type="gchararray"/>
<!-- column-name Message -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow" id="window_info">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Info</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow_info">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="min_content_width">400</property>
<property name="min_content_height">600</property>
<child>
<object class="GtkTreeView" id="treeview_info">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">liststore_info</property>
<property name="enable_search">False</property>
<property name="enable_grid_lines">both</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview_info_selection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="treeview_info_column_time">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="min_width">100</property>
<property name="title" translatable="yes">Time</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText" id="treeview_info_cellrenderer_time"/>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="treeview_info_column_message">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="min_width">300</property>
<property name="title" translatable="yes">Message</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText" id="treeview_info_cellrenderer_message"/>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
When I compile and run this code (plus one call to info_handler()) I get a treeview with one row and two blank columns. When I uncomment the two lines appending the columns, I get a treeview with one row and four columns. The first two columns are blank (and sized according to the glade file) and the second two have the "Now" and msg strings (and are sized automatically to the contents).
What I gather from this is that elements.info_columns is not associated with elements.treeview_info via elements.liststore_info. It looks like I'm just missing a step to connect the two. liststore_info is listed as the model for treeview_info in the glade file, as well as being set in GuiManager's constructor.
Where's the disconnect?

I think you need to set which list store field should be displayed in each table column.
In Glade, right-click on the tree widget and click Edit... (not Edit separately)
Click on the Hierarchy tab
Click on a column
Under Properties and Attributes ensure Text is ticked and the correct list store column is chosen from the drop down list (which will update the index accordingly.) For Pixbuf columns, you want Pixbuf Object instead of Text.
Repeat for each column
In your case, I believe you should end up with an index of 0 for the Time column, and 1 for the Message column, and -1 in all the other fields.
This will populate the column's text from the selected field in the list store. I believe it's done this way so you can populate a column's other attributes (font, colour, etc.) through the list store as well, if you want.
Unrelated to this, I would also consider changing Gtk::TreeModelColumn<string> to Gtk::TreeModelColumn<Glib::ustring> as I believe the way you have it now may cause a conversion to/from a Glib::ustring every time the tree view redraws itself. Keeping it as a Glib::ustring from the start should avoid most of this conversion.

Related

How to get json property when I use the Property Mediator?

I use the Property Mediator to get a registry resource, it returns me a json string, but how can I get the property in the json string?
my code example:
test-file.json like so
{
"mappings": {
"mapping": {
"ep_1": "http://localhost:8280/services/ep_1",
"ep_2": "http://localhost:8280/services/ep_2",
"ep_3": "http://localhost:8280/services/ep_3"
}
}
}
I do like this:
<property expression="get-property('registry','conf:customresource/test-file.json')" name="JsonContent" scope="default" type="STRING"/>
<property expression="????" name="endpointUrl" />
how to get the property 'ep_1' in the 'endpointUrl' Or is there any other way to get the property 'ep_1'? thx
Try the following.
expression="json-eval($ctx:JsonContent.mappings.mapping.ep_1)"
If above does not work, try this.
expression="$ctx:JsonContent//mappings/mapping/ep_1"
Saving the input JSON to a property:
<property expression="json-eval($)" name="var_in_JSON" scope="default" type="STRING"/>
!!! Don't use dots (.) in the json property name !!!
...
Using data from a saved json property:
<property expression="json-eval($ctx:var_in_JSON.sub_param)" name="sub_param" scope="default" type="STRING"/>
The answer in your case:
<property expression="json-eval($ctx:JsonContent.ep_1)" name="ep_1" scope="default" type="STRING"/>
You can load json file from registry to payload, and make json-eval on payload. It is dirty solution, but it works ;):
<property expression="base64Decode(get-property('registry','conf:customresource/test-file.json'))" name="JsonContent" scope="default" type="STRING"/>
<payloadFactory description="Build Payload Response" media-type="json">
<format>$1</format>
<args>
<arg evaluator="xml" expression="$ctx:JsonContent" xmlns:payload="http://ws.apache.org/commons/ns/payload"/>
</args>
</payloadFactory>
<property expression="json-eval($.mappings.mapping.ep_1)" name="endpointUrl" scope="default" type="STRING"/>
Best regards
I have done with this question.You have to use XML content instead of JSON, then set content into a Property Mediator which type filed is OM, and you can use xpath expression to get any value you want in your XML content.
code example
XML content:
<mappings>
<mapping>
<ep_1>http://localhost:8280/services/ep_1</ep_1>
<ep_2>http://localhost:8280/services/ep_2</ep_2>
<ep_3>http://localhost:8280/services/ep_3</ep_3>
</mapping>
</mappings>
<property expression="get-property('registry','conf:customresource/test-file.xml')" name="XmlContent" scope="default" type="OM"/>
<property expression="$ctx:XmlContent/mapping/ep_1" name="endpointUrl" />
After that, the value will been set into the property named endpointUrl.
Last, please note the expression of second Property mediator,you get black value if you do like this $ctx:XmlContent/mappings/mapping/ep_1.Hope its helpful for someone.

Hybris Custom WSDTO on hybris product data

Hi I had created eProductForm bean in the commerecefacades-beans.xml I added custom attribute of ProductData.
<bean class="de.hybris.platform.commercefacades.product.data.ProductData">
<property name="eProductForm" type="String"/>
</bean>
then in commercewebservice-beans.xml, I added the custom attribute of ProductWsDTO
<bean class="de.hybris.platform.commercewebservicescommons.dto.product.ProductWsDTO">
<property name="eProductForm" type="String"/></bean>
from SearchResultProductPopulator populated productdata of eProductForm from my search result.
target.setEProductForm(this.<String> getValue(source, "E_PRODUCT_FORM"));
PFB
dto mapping
<bean parent="fieldSetLevelMapping" id="productWsDTOFieldSetLevelMapping">
<property name="dtoClass" value="de.hybris.platform.commercewebservicescommons.dto.product.ProductWsDTO"/>
<property name="levelMapping">
<map>
<entry key="BASIC"
value="purchasable,stock,name,baseProduct,availableForPickup,code,url,price"/>
<entry key="DEFAULT"
value="summary,averageRating,purchasable,stock(DEFAULT),description,variantMatrix(DEFAULT),name,baseOptions(DEFAULT),baseProduct,availableForPickup,variantOptions(DEFAULT),code,url,price(DEFAULT),numberOfReviews,manufacturer,categories(BASIC),priceRange,multidimensional,configuratorType,configurable,tags"/>
<entry key="FULL"
value="summary,productReferences(FULL),classifications(FULL),averageRating,purchasable,volumePrices(FULL),variantType,stock(FULL),description,variantMatrix(FULL),name,baseOptions(FULL),baseProduct,availableForPickup,variantOptions(FULL),reviews(FULL),code,url,price(FULL),numberOfReviews,manufacturer,volumePricesFlag,futureStocks(FULL),images(FULL),categories(FULL),potentialPromotions(FULL),priceRange,multidimensional,configuratorType,configurable,tags,eProductForm,ePickledGroup"/>
</map>
</property>
</bean>
Below is the code I am calling Mapper.. While I debugged my code sourceresult is having product data of that custom attreibute. But I am not getting the eproductform in the WSDTO response.
final ProductSearchPageData<SearchStateData, ProductData> sourceResult = searchProducts(query, currentPage, pageSize, sort);
if (sourceResult instanceof ProductCategorySearchPageData)
{
return getDataMapper().map(sourceResult, ProductCategorySearchPageWsDTO.class, fields);
}
But in logs I see:
[EL Warning]: 2019-02-20 18:31:27.341--Ignoring attribute
[eProductForm] on class
[de.hybris.platform.commercewebservicescommons.dto.product.ProductWsDTO]
as no Property was generated for it.
As #Farrukh Chishti commented, the URL that you used probably used the DEFAULT level, which doesn't contain the attribute you added. For testing purposes, you can try to add the attribute to BASIC, DEFAULT, and FULL.
In the URL, you can specify the level, something like this:
https://localhost:9002/rest/v2/custom_site/stores?&fields=FULL

Enrich Payload in WSO2

I have a JSON array of the following structure.
{"paymentItems": [
{
"amount": "180000",
"code": "28"
},
{
"amount": "396000",
"code": "06"
},
{
"amount": "1460000",
"code": "01"
}
]
}
Am trying to enrich each item in the array list with an additional JSON value.
<foreach expression="//paymentItems" id="1">
<sequence>
<property expression="//paymentItems/amount" name="amount" scope="default" type="STRING"/>
<property expression="//paymentItems" name="body" scope="default" type="STRING"/>
<log>
<property expression="$ctx:amount" name="INIDIVIDUAL_AMOUNT"/>
</log>
<script language="js"><![CDATA[var amount = mc.getProperty('amount'); var naira = amount/100; mc.setProperty("nairaValue", naira);]]></script>
<log>
<property expression="get-property('nairaValue')" name="NAIRA_VAL"/>
</log>
<property expression="get-property('nairaValue')" name="naira" scope="default" type="STRING"/>
<enrich>
<source type="custom" xpath="$ctx:nairaValue"/>
<target action="child" type="body"/>
</enrich>
</sequence>
</foreach>
As you can see I process the value in the foreach and then use the result and try to add to the array item but it throws no errors and does not add the value.
Foreach mediator does the following
first take a clone of the original message
take an iterated element from the original message (using XPath)
Create a new message context by adding the iterated element to the cloned envelope
Do the mediation steps given in the sequence for that new message context
Since for each iteration, we are cloning a new message context (say context2), and the original message context(say context1) is a separate one, we cannot enrich from context2 to context1.
That's the reason for the behaviour you are experiencing.
As a remedy, you can do the iteration itself from the script mediator and alter the message as required.

XSLT: Xpath to count items with attribute value matching another specific sibling

I have the following (simplified; there are more Property-Lines) XML-File that I need to process by XSLT:
<Collection Name="Columns" Type="OutputColumn">
<SubRecord>
<Property Name="Name">SID</Property>
<Property Name="SqlType">BigInt</Property>
<Property Name="Derivation">inputstream1.SID</Property>
<Property Name="Description">Main key</Property>
</SubRecord>
<SubRecord>
<Property Name="Name">name</Property>
<Property Name="SqlType">Char</Property>
<Property Name="Derivation">inputstream2.name</Property>
<Property Name="Description">Surname</Property>
</SubRecord>
<SubRecord>
<Property Name="Name">street</Property>
<Property Name="SqlType">Char</Property>
<Property Name="Derivation">inputstream1.streetname + inputstream1.number</Property>
<Property Name="Description">Full street</Property>
</SubRecord></Collection>
I now need to know two things as a variable in XSLT to decide what to do further in an if-Condition:
Is there at least one SubRecord where substring-after(Derivation, '.') matches the sibling Property "Name" (so like in the first two SubRecords)?
Is there at least one SubRecord where substring-after(Derivation, '.') does not match the sibling Property "Name" (so like in the third SubRecord)?
I tried to do this by Xpath with the Count()-Functionality but simply can't figure out how to do the comparison to the sibling Property node with "Name" as it's name...I'm also open for other ideas if you know an alternative to Count().
I'm not sure I completely understood the issue, so check below and let me know if it's not what you actually want
First can be done with below XPath:
boolean(//SubRecord[substring-after(./Property[#Name="Derivation"]/text(), '.')=./Property[#Name="Name"]/text()])
This should return true because XPath matches first two SubRecord elements.
Using not() should allow to return true because XPath matches third SubRecord element:
boolean(//SubRecord[not(substring-after(./Property[#Name="Derivation"]/text(), '.')=./Property[#Name="Name"]/text())])

XSLT - Accessing Key's by index - For example, in Muenchian Grouping

<listings>
<property rln="r317080" firm="f102" agent="a2140">
<street>2638 Maple Avenue</street>
<city>Padua</city>
<state>WI</state>
<zip>53701</zip>
<price>229000</price>
<style>2 Story Contemporary, Transitional</style>
<sqfeet>2328</sqfeet>
<bathrooms>2 1/2</bathrooms>
<bedrooms>4</bedrooms>
<garage>2 car, attached</garage>
<age>22</age>
<description>Very nice home on a one block dead end street with woods nearby.
Very special location for quiet and privacy! Home features open floor plan with
large rooms - new patio doors to pretty yard. updates: shingles, vinyl siding,
refrig and dishwasher, garage door. Fireplace in family room flanked by great
built-ins. add first floor laundry and award winning Padua schools.
</description>
</property>
<property ...>
<city>Broxton</city>
...
</property>
<property ...>
<city>Cutler</city>
...
</property>
<property ...>
<city>Argyle</city>
...
</property>
<property ...>
<city>Stratmore</city>
...
</property>
<property ...>
<city>Padua</city>
...
</property>
<property ...>
<city>Oseola</city>
...
</property>
<property ...>
<city>Fenmore</city>
...
</property>
<property ...>
<city>Cutler</city>
...
</property>
<property ...>
<city>Padua</city>
...
</property>
<property ...>
<city>Cutler</city>
...
</property>
<property ...>
<city>Oseola</city>
...
</property>
</listings>
In my textbook (XML 2nd Edition by Patrick Carey) it provides an example of using 'Muenchian Grouping' to find unique selections. The part I don't understand is thus:
It gets to here, in the progression of the example where it states: "
property[generate-id()=generate-id(key("cityNames", "Cutler")[1])]
" which says that this will find the first 'Cutler' in the selection, due to the index of '[1]'. Which given the XML above will return "Cutler"
Now the example progresses to thus: "
property[generate-id()=generate-id(key("cityNames", city)[1])]
" which says that this will find the first and only the first (therefore unique) of each city within the key. Creating a group of unique values of all the city's within. Which given the XML above will return "Argyle Broxton Cutler Fenmore Padua Stratmore Oseola" (note that there is no multiples).
Now, my question is thus: why does the second statement return a range of values, instead of just one?
Thanks
When you define your key, the match expression can match multiple nodes. That node-set is returned when accessing the key by name.
Adding the predicate filter for the first one ensures that you will only get at most one(the first) node returned from the key.
Ok, I suppose the answer I was looking for is thus:
property[generate-id()=generate-id(key("cityNames", city)[1])]
This code finds the first of each city
property[generate-id()=generate-id(key("cityNames", city[1]))]
and this code finds the first of all city's
easy enough, just couldn't see it before.