NSTokenField click completion list item - objective-c

I have an NSTokenField in my application and I implemented the tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem: method in which I specify the receiver’s tokenizing character set with the setTokenizingCharacterSet: method:
def tokenField(tokenField, completionsForSubstring:substring, indexOfToken:tokenIndex, indexOfSelectedItem:selectedIndex)
tokenField.setTokenizingCharacterSet(NSCharacterSet.whitespaceAndNewlineCharacterSet)
end
It works as expected when I click on the space bar or the enter button. I would also like to have the same behavior when I click on one of the item of the completion list with my mouse.
How is that possible?
Thanks for your help.

I don't know if it's possible to have this behaviour with a NSTokenField.
But you should take a look at MTTokenField which do what you want out of the box.
To do so, you will have to:
1.Create an Xcode Project as a Static Library(Do not enable ARC).
2.Save your project to vendor/MTTokenField
3.Drag and drop all the files of MTTokenField located in the subdirectory 'MTTokenField' to your new XCode project. Choose to copy the files.
4.Add this to your rakefile in order to compile and link the library with your Rubymotion project.
app.vendor_project("vendor/MTTokenField/", :xcode, :xcodeproj => "MTTokenField.xcodeproj", :target => "MTTokenField", :products => ["libMTTokenField.a"], :headers_dir => "MTTokenField")
5.In Interface Builder change the class of your NSTokenField to NSTextField and then set its custom class to MTTokenField, and also change the custom class of the cell: MTTokenFieldCell instead of NSTextFieldCell.
6.Then you have to set the delegate of your MTTokenField to a class which has to respond to :
def tokenField(tokenField, completionsForSubstring: substring )
# your have to return an array containing your results matching substring.
end
And that's it. It should work.
Hope it helps !

I found another solution using NSTokenField instead of MTTokenField.
In the delegate of my NSTokenField, I used the controlTextDidChange method of NSControl which is called anytime I write a character in my token field. In this method I check if there is a NSLeftMouseUp event which is triggered, and if it's the case, I simulate a click on Return. And that's it.
def controlTextDidChange(aNotification)
application = NSApplication.sharedApplication
event = application.currentEvent
if event.type == NSLeftMouseUp
e1 = CGEventCreateKeyboardEvent(nil, 0x24, true)
CGEventPost(KCGSessionEventTap, e1)
end
end
There is one more thing to do to make it properly work: the issue here is that if I have a completion list with 3 items for instance, one of them will be selected by default, let's say the first one. In this case, the solution will work as expected if I click the second or the third item but I will have to double click the first item to make it work.
To fix this, turn off the autocompletion and only display the suggestion box, i.e add this line to the tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem: method:
selectedIndex[0] = -1

Related

How should a test be written for a delegate for editing?

I have a tree view for which some fields need to use a custom delegate for editing. The delegate presents a QListView for value selection. It seems like the QAbstractItemView.edit() method should be used to initiate the edit from the test but I can't figure out how to get access to the created editor (a QListView) so I can select the proper element for the test.
This is part of a test I had working with a QComboBox delegate before switching to the QListVew, but it seems too manual.
for index, enumerator in enumerate(group.children):
editor = delegate.createEditor(
parent=viewport,
option=None,
index=target_index,
)
editor.setCurrentIndex(index)
delegate.setModelData(editor, model, target_index)
assert enumerator.uuid == item.enumeration_uuid
https://github.com/altendky/st/commit/643c5c30f87fc3bfd8b422687e81f740ec36ef44#diff-06bc81dbbd9f7a12878169d5238e1572R846
Here is what I came up with.
https://github.com/altendky/st/blob/089432162b9e8ca67eafdfcc2a4ecc34e8f0e96e/epyqlib/tests/test_attrsmodel.py#L848
for row, enumerator in enumerate(group.children):
assert view.edit(
target_index,
PyQt5.QtWidgets.QAbstractItemView.AllEditTriggers,
None,
)
editor, = view.findChildren(PyQt5.QtWidgets.QListView)
index = editor.model().index(row, 0, editor.rootIndex())
editor.setCurrentIndex(index)
editor.clicked.emit(index)
# this is fun. if you get weird issues try doing this more times
for _ in range(3):
application.processEvents()
assert enumerator.uuid == item.enumeration_uuid
Do note that I connect the editor's clicked signal to post an enter-key event since the view's are hardcoded to catch an enter event and finish editing.

Call Pop-Up for WebDynpro from a Business AddIn?

We got a Web Dynpro Application which was created with the Floorplan Manager.
By clicking a specific button I start a Business AddIn which check some conditions and then it should show a popup on the screen with a message for the user.
Is there a way I can accomplish that?
One way to get a PopUp (eg confirmation) window in Floorplan applications is to overwrite the NEEDS_CONFIRMATION method of the Interface IF_FPM_GUIBB_*_EXT inside your feeder-class.
Create a reference to cl_fpm_confirmation_request and put this one in the export-parameter EO_CONFIRMATION_REQUEST of the Method.
By Example:
METHOD if_fpm_guibb_list_ext~needs_confirmation.
DATA li_req TYPE REF TO cl_fpm_confirmation_request.
CASE io_event->mv_event_id.
WHEN 'YOUR_EVENT_ID'.
CREATE OBJECT li_req
EXPORTING
it_confirmation_text = 'Plaintext in Content of Popup'
iv_window_title = 'Title of the Popup'
iv_button_text_approve = 'Text Approve-Button'
iv_button_text_reject = 'Text Reject-Button'
.
eo_confirmation_request = li_confrequ.
ENDCASE.
ENDMETHOD.
The method will be called before the PROCESS_EVENT-Method an will override it when you cancel the popup.
Please be aware that every GUIBB-Implementation has it´s own extension interface, e.g. List, Tree, ...
For a deeper look inside popups in FPM or custom-popups have a look into https://blogs.sap.com/2013/11/26/popups-in-floorplan-manager/

TableView delete column via contextual menu

It is my first time asking here, sorry if i do something wrong (also not in my mother tongue).
Recently, i moved from Swing&AWT to JavaFX.
I am discovering the new Table which is quite different from the Swing version. Better i would say, it needs less operation and do more things, but ... lord, it's way more difficult to understand !
I am currently trying to modify the TableView dynamically. While the addColumn method is not a big challenge, i need help for my deleteColumn method :/
Let's talk about my problem :
I have a scene with many components on it (panes, buttons, menus, ...) and one pane (actually an anchorpane) hosts a TableView.
I would like to dynamically delete an entire column when this operation occurs :
The user right clicks on the TableView > a contextual menu shows up > he selects the item "delete"
So, basically a contextual menu that offers the option to delete the column where the user right-clicked.
I tried this :
-> When the user right-clicks on the TableView, this method is called :
public void setTargetForContext(ContextMenuEvent event){
if(event.getTarget() instanceof Label){
ObservableList list =(((Label)event.getTarget()).getChildrenUnmodifiable());
activeColumn = ((Text)((ObservableList)list)).getText();
}...
And the goal was to set the column name in "activeColumn".
Then, when the user will select the "delete" option from the contextual menu, another method would be called to compare the name of the columns and delete the right one.
But it seems that i can't call a getChildren() method on the label, only an unmodifiable one. And it does not allow a cast and throw the exception.
Do you have a solution to allow me to get the column name ?
Or maybe i am going the wrong way and i have to find another way to delete the right-clicked column, but in this case i will need your help too.
Thanks a lot for reading, and thanks in advance for your help.
First, let me point out that if you call
table.setTableMenuButtonVisible(true);
then the table will have a built-in menu button with radio buttons allowing the user to select which columns are displayed. Maybe this is all you need.
In Swing, the renderers for table cells are just "rubber stamps" that are painted onto the table. Thus you can't register listeners for UI events with them.
By contrast, in JavaFX, the cells in a table are real UI controls with full functionality. This means there's no real need for API that gets the cell coordinates from a table. You should not register your listener with the TableView, but with the actual cells on which you want to operate. You access the cells from the table column's cell factory.
// the table:
TableView<RowDataType> table = new TableView<>();
//...
// A table column:
TableColumn<RowDataType, CellDataType> column = new TableColum<>("Header text");
// A context menu for the table column cells:
ContextMenu contextMenu = new ContextMenu();
MenuItem deleteColumnItem = new MenuItem("Remove Column");
deleteColumnItem.setOnAction(e -> table.getColumns().remove(column));
contextMenu.getItems().add(deleteColumnItem);
// Cell factory for the column
column.setCellFactory(col -> {
// basically a cell with default behavior:
TableCell<RowDataType, CellDataType> cell = new TableCell<RowDataType, CellDataType>() {
#Override
public void updateItem(CellDataType item, boolean empty) {
super.updateItem(item, empty);
if (item == null) {
setText(null);
} else {
setText(item.toString());
}
}
});
// add the context menu to the cell:
cell.setContextMenu(contextMenu);
return cell ;
});
If you want the context menu to appear in the table column header as well, you just need to do
column.setContextMenu(contextMenu);

How to automate a splitButton using Rautomation ( adapter msuia)

I am trying to automate IE11 notification bar ( while downloading file) using Rautomation. Using MSUIA adapter I am able to catch the the save button. But I want to use Save As to supply the file location and name. But I cannot do that.
When seeing with UIspy I see that there is a splitbutton with name "Save". This splitbutton has another child splitbutton with name "" ( which is basically the down arrow) - I am not able to get to this control.
iemainwindow_local = RAutomation::Window.new(:class=>"IEFrame" , :adapter => :ms_uia )
ienotificationbar_frame = iemainwindow_local.child(:class=>"Frame Notification Bar")
ienotificationbar = ienotificationbar_frame.child(:class=>"DirectUIHWND")
if ienotificationbar.exists?
ienotificationbar.activate
sleep 1
mycontrol = ienotificationbar.control(:value =>"Save")
mycontrol2= mycontrol.control(:children_only => true)
mycontrol2.exist?
mycontrol.click
end
Getting error at this line mycontrol2= mycontrol.control(:children_only => true)
undefined method `control' for #<RAutomation::Adapter::MsUia::Control:0x4108e60>
Any idea how to get over this block?
I understand that there should be a menu and menuitems associated with the splitButton and when I click on down arrow besides Save, at UISpy I see that menu/ menu item is getting created directly under Desktop window ( though the processID is same ) - how to catch the menuitem Save as?
The Problem
Unfortunately, the :ms_uia adapter for RAutomation is not able to do this in its current form. I know this because I have written a lot of the UIA adapter for it :) The problem is that the current API doesn't allow you to really walk the tree like that (as you found out) because the Control class doesn't have a #control method. If the "Save" button had a native window handle, you'd be able to do this:
ieframe = RAutomation::Window.new(class: 'IEFrame')
save = RAutomation::Window.new(hwnd: ieframe.control(value: 'Save').hwnd)
save.control(index: 0)
Since it does not, unfortunately there isn't a reliable way to get down to it that I am aware of since it doesn't have any identifying properties about it (other than being a child of the "Save" button).
Alternative
I've written another gem called uia, which acts as a low-level wrapper around UI Automation and allows you to work more closely with UI Automation and interact with it how you see it within tools like UI Spy. Eventually, I will use this gem in RAutomation but have not had the time yet. To get down to the "Save As..." split button control in your circumstance, you can do this:
ieframe = UIA.find_element(title: /Thanks for downloading/)
save_as = ieframe.find(name: 'Save').find(control_type: :split_button)
save_as.as(:invoke).invoke
The save_as.as(:invoke) will treat the found "Save As" Element as something that implements the Invoke pattern, and then you can call the #invoke method to get the menu to pop.
Hope this helps!

NSTokenField completion list style

I'm a beginner in OSX development so I hope my question will find a solution here.
I have an NSTokenField in my app and I implemented the tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem: method.
Everything works fine but the present result look like this :
What I would like is to make it look like this: (similar to the completion in the Mail app)
Which means that I would like the completion list to take all the NSTokenField width.
Using the Accessibility Inspector, I can see that the hierarchy corresponding to the first sreenshot is:
AXScrollArea -> AXList -> AXTextField
while the one corresponding to the second screenshot is:
AXScrollArea -> AXTable -> AXRow:AXTableRow -> AXTextField
So I suppose I have to use an NSTableView to display the completion list, but I don't know how to achieve this. Does anybody know how is that possible?
Thanks in advance for your help.
EDIT
At least 2 people suggested that I implement the tokenField:menuForRepresentedObject: method and define the menu width with the appropriate NSMenu property. But this method is used to define a menu for a given token and I already implemented it:
def tokenField(tokenField, menuForRepresentedObject:representedObject)
theMenu = NSMenu.alloc.initWithTitle("Email address context menu")
item_0 = theMenu.insertItemWithTitle('add_to_address_book'.localized, action:'add_to_address_book', keyEquivalent:"", atIndex:0)
item_0.setTarget(self)
item_1 = theMenu.insertItemWithTitle('new_message'.localized, action:'new_message', keyEquivalent:"", atIndex:1)
item_1.setTarget(self)
theMenu
end
Which gives me something like this:
Something great but not what I am asking here.