JavaFX - How to synchronize CustomTab (extending Tab) and TabPane - java

I am developing an IDE. I created a CustomTab.java class by extending the default JavaFX Tab. I wanted to add a color transition animation, but I ran into a problem. The method in TabPane named getTabs(), which returns ObservableList<Tab>, is final. This means I can't override it to return ObservableList<CustomTab>. It seems that constructions like this:
for (Tab tab : tabPane.getTabs()) {
((CustomTab) tab).stopFlash();
}
used in Controller.java are neck breaking and wrong.
What is the right way to do this?

I think my reply is quiete late, but I think there is a way to do so.
Use the function
tab.setUserData(Object c);
In that Object you can store all the informations you'll need to proceed.
so for example create an Object holding all the objects you need.
E.g. you can hold the reference to your webView.
Also if you need to have different informations you could use:
tab.getProperties().put(Object key, Object data);
// receive the value with
tab.getProperties().get(key);
Here a link to the documentation I found
Maybe the Javadoc is better, but I found this one.
Here is a little example that I wrote:
public SQLEditorTab getNewTab(){
SQLEditorTab tab = new SQLEditorTab("new Tab " + number);
tab.setId("newTab" + number);
tab.setOnCloseRequest(this);
tab.setUserData(tab.tabContent);
number ++;
return tab;
} // just to create the tab
In my listener I receive the result simply by:
sqlEditorPane.getTabs().forEach((Tab t) -> {
if(t.getUserData() != null){
System.out.print(t.getUserData().getClass());
}
});

Related

How to perform custom navigation through JFace Eclipse Wizard pages?

I have Eclipse JFace wizard with five pages. In the first, I have check buttons to select which pages are to be shown - if you check all, you will pass through the whole wizard, but you can also select only specific pages, and then only that pages will be shown.
So far, I used iterator with enum objects representing each page. I called next object of iterator in getNextPage function and its if..else cases to return certain pages in proper order. The problem is, getNextPage is called not only when Next button is pressed, but also when pageComplete event firing, etc. so iterator does not update its cursor when I want, and it ends up to fast. This is snippet of my assumption:
else if(page == FirstPage )
{
// iterator contains SelectedAction - enum objects representing pages
this.pageIterator = page.getWizardPagesList().iterator();
if(pageIterator.hasNext())
{
return selectedActionToPage(pageIterator.next());
}
}
else
{
if(pageIterator.hasNext())
{
SelectedAction action = pageIterator.next();
if(!pageIterator.hasNext())
{
// we check if current page was last one
setFinished(true);
setLastPage(selectedActionToPage(action));
}
// selectedActionToPage converts enum object to WizardPage class
return selectedActionToPage(action);
}
else if((pageIterator != null) && !pageIterator.hasNext())
{
return page;
}
}
return page;
Especially, things I want to know are:
First, is there any other way to capture Next button click? I know there is NextPressed method in WizardDialog class, but I don't know how to call its instance from my Wizard class, or WizardPage.
Second, is there other way to customize navigation through pages, to go to specified pages?
No, you should not try to intercept the Next button click that logic is private to the wizard dialog and you should not be trying to interfere with it,
You can either override the WizardPage:
public IWizardPage getNextPage()
method or you can override the Wizard
public IWizardPage getNextPage(IWizardPage page)
You may also need to override the matching getPreviousPage method. You must make your code work regardless of when the method is called. You are given the information about which is the current page, your code should use that to determine the next page.

JavaFX ListView adding item into observable list doesn't reflect change and it's not selectable

I have run into pretty messed up behaviour with my ListView, I have listview created in controller with data attached to it.
#FXML
private ListView<Weapon> listViewWeapons;
...
private final ObservableList<Loadout> loadoutList;
public LoadoutViewController() {
...
loadoutList =FXCollections.observableList(CsgoRr.getModel().getLoadoutCache());
...
}
#Override
public void initialize(URL location, ResourceBundle resources) {
...
listViewLoadouts.setItems(loadoutList);
...
}
I call method attached to button, which has function of adding new loadout into list
#FXML
private void newLoadoutOnAction() {
try {
Loadout loadoutToBeStored = new Loadout(new Long[10], "Loadout" + newDuplicateNameLoadoutIncrement);
loadoutToBeStored.setId(DbUtil.storeLoadout(loadoutToBeStored));//store and set id.
CsgoRr.getModel().getLoadoutCache().add(loadoutToBeStored);
System.out.println("Stored new loadout ");
listViewLoadouts.getSelectionModel().select(loadoutToBeStored);
for (Loadout loadout : loadoutList) {
System.out.println("DEBUG LOADOUT CONTAINER OBSERVABLE:" + loadout);
}
} catch (SQLException ex) {//duplicate name
if (ex.getErrorCode() == 23505) {
newDuplicateNameLoadoutIncrement++;
newLoadoutOnAction();
}
Logger.getLogger(LoadoutViewController.class.getName()).log(Level.SEVERE, null, ex);
}
}
All the data is correctly loaded and stored, I have debugged that part of course. But even though I call method newLoadoutOnAction and I put data into list which observable list has reference to, change is not seen up until I resize that listView. That's not the only problem, even after I resize listView and I'm able to see item in a list I can't select it I have to call construstor and initializer again to be able to select this item. I have never encountered this behaviour, how do I fix these problems?
Problem with refreshing item in the list: I have tried to remove items and set them again, and some other solutions common to this problem bud nothing worked even if I put setItems(null) I can't get it to work, items are still there.
Latest item inserted is not selectable (through UI) until I call my controller again and recreate everything. I have this item selected with code.
listViewLoadouts.getSelectionModel().select(loadoutToBeStored);
This actually selected needed item bud I don't see any feedback in the UI and I can't select it with my mouse. Even if I remove this line I still can't select it with a mouse till I call my view again (constructor and initializer).
I know this is a bit more complex problem so I decided to show you what's happening with a gif.
Hope it's clear.
The Javadoc for FXCollections.observableList states:
Note that mutation operations made directly to the underlying list are not reported to observers of any ObservableList that wraps it.
For this reason loadoutList is not connected to the list in CsgoRr.getModel().getLoadoutCache() after creation. This means that when newLoadoutOnAction() calls:
CsgoRr.getModel().getLoadoutCache().add(loadoutToBeStored);
it is not picked up by loadoutList, or the ListView watching it. If you change CsgoRr.getModel().getLoadoutCache() to use an ObservableList, and assign that directly to loadoutList your function should work as desired.
The other option would be to add your loadoutToBeStored to loadoutList instead, but then you would need to also synchronise with the List in CsgoRr.getModel()

Combobox doesn't react to ".setValue()" nor ".select()"

This is my code:
comboBoxInstance.setInputPrompt("Something...");
comboBoxInstance.setNullSelectionAllowed(false);
Cookie comboCookie = getCookieByName("combo");
comboBoxInstance.select((comboCookie != null) ? comboCookie.getValue() : null);
final TextField textFieldInstance = new TextField("Textfield");
textFieldInstance.setInputPrompt("Something...");
Cookie tfCookie = getCookieByName("tf");
textFieldInstance.setValue((tfCookie != null) ? tfCookie.getValue() : null);
The problem is that the textfield works pretty well with the "Cookie setup". Only the combobox is refusing to work like it should.
The output is like this:
I've tried to use .setValue() instead of .select() but this has pretty much the same effect. I've also made sure that both the Cookie itself and the correct value are provided.
It may help to have a look at the part where the cookie is generated:
Cookie comboCookie = new Cookie("combo", comboBoxInstance.getValue().toString());
cookieProcessing(costcentreCookie); //<- sets maxage and vaadin related stuff (like adding the cookie)
Edit:
A few points to the data flow.
I'm generating a ComboBox with a SimpleJDBCConnectionPool's SQLContainer as the data container (coming from a TableQuery). Here's the initialization (executed in the constructor) in the combobox class:
private void init() throws SQLException {
this.setContainerDataSource(generateContainer());
this.setItemCaptionPropertyId("something");
}
The private method generateContainer() returns the SQLContainer of course.
This happens if I click on a particular button which opens up a dialog. This dialog is the fragment shown in the picture above. The combobox - of course - is part of it.
What one is supposed to do now is setting his data (get an item of the ComboBox) and hit save. The save button executes the routine to store the cookies. It's the code already mentioned above (Cookie comboCookie = new Cookie(...).
Okay, now the user is going to open up the dialog again. It's not important whether he reloads the application or just reopens the dialog (or does something else). It's basically the same in the app.
The dialog opens up and initializes the combobox (and the textfield) once again. However, this time it's supposed to gather the data out of the stored cookies. This is were the issue happens. This works well for the textfields (there are two but I've omitted one for shortening reasons) but not for the combobox, even tough it should've the exact same data as before. Hold in mind that it's the exact same class with the exact same initialization as when we stored the cookies in the first place.
I've the vague presumption, that it has to do something how the code is stacked. Maybe it hasn't finished loading the datacontainer while trying to set the appropriated value which then can't be found.
Edit2:
I've finally managed to reveal something. The ComboBox is indeed empty when the ".select()" is executed. However, this means, that the ComboBox is left untouched (it's only kind of "linked" to the datacontainer) until someone drops down the items. As soon as this happens, the items are there and I can possibly select them.
Is it supposed to work like this? O.o Am I able to fully initialize the combobox before I do something else? Something like:
private void init() throws SQLException {
this.setContainerDataSource(generateContainer());
this.setItemCaptionPropertyId("something");
this.gatherTheItems();
}
Edit3 - Test with ".setImmediate(true)"
I've changed the init to:
private void init() throws SQLException {
this.setContainerDataSource(generateContainer());
this.setItemCaptionPropertyId("SOMETHING");
this.setImmediate(true);
}
This didn't change anything. The combobox is still empty:
Finally! At first I've found a workaround which was like this:
for (Iterator it_IDS = combobox.getItemIds().iterator(); it_IDS.hasNext();) {
Object id = (Object) it_IDS.next();
if(id.toString().equals(cookie.getValue().toString())){
combo2.select(id);
break;
}
}
However, I couldn't believe that this was working since it doesn't change anything at the core problem. So I've investigated, that the RowID is built via a BigDecimal and voilĂ :
if(cookie != null) {
combobox.select(new RowId(new BigDecimal(cookie.getValue())));
}
I'm so happy right now :) Thanks for your patience kukis.
In case you came here because you're experiencing the same issue using a BeanItemContainer as datasource, bear in mind that you must implement both equals()and hashCode() methods on the underlying class for ComboBox's select() or setValue() methods to work.
You have plenty examples on Vaadin Forum on how to implement these methods:
ComboBox select value problem
Select or ComboBox does not Show Selected Property
Combobox select/setValue

Adding figures using contextual menu - Eclipse GEF

All,
I am creating a palette less eclipse plugin where am adding figures to the custom editor through the contextual menu, but am not finding a way to do it. Can anyone please guide me as to how to go about adding figures to editor dynamically through context menu i.e. adding actions/commands.
Since Eclipse GEF plugin development finds so less examples to look at, I am adding my solution so others find it useful. This code helps to render a node to the editor.
Source code for Action class to render figures to the editor:
public class AddNodeAction extends EditorPartAction
{
public static final String ADD_NODE = "ADDNODE";
public AddNodeAction(IEditorPart editor) {
super(editor);
setText("Add a Node");
setId(ADD_NODE); // Important to set ID
}
public void run()
{
<ParentModelClass> parent= (<ParentModelClass>)getEditorPart().getAdapter(<ParentModelClass>.class);
if (parent== null)
return;
CommandStack command = (CommandStack)getEditorPart().getAdapter(CommandStack.class);
if (command != null)
{
CompoundCommand totalCmd = new CompoundCommand();
<ChildModelToRenderFigureCommand>cmd = new <ChildModelToRenderFigureCommand>(parent);
cmd.setParent(parent);
<ChildModelClass> newNode = new <ChildModelClass>();
cmd.setNode(newNode);
cmd.setLocation(getLocation()); // Any location you wish to set to
totalCmd.add(cmd);
command.execute(totalCmd);
}
}
#Override
protected boolean calculateEnabled()
{
return true;
}
}
I think you need multiple different things here. Please remember that GEF would like you to have proper MVC pattern, where you have your own model, Figures as View and EditParts as controllers.
From the top of my head I would say that you need at least these things:
CreateCommand
contains all model level modifications that you need to
perform to add your new data to your
data model (undoable and transactional)
CreateAction
makes that CreateCommand instance, initializes it with current selection and executes that command in editdomain
ContextMenuProvider
Provides that CreateAction to context menu
If you happen to be using GMF the canonical mechanism will generate the editparts for you automatically when you make the model modifications inside a command, but if you are not using GMF, you must make sure that your own models and editparts are handling and refreshing the new item adding properly.
EDIT:
Ok, here is some code suggestion with playing around with requests.
public void run() {
// Fetch viewer from editor part (might not work, if not, try some other way)
EditPartViewer viewer = (EditPartViewer) part.getAdapter(EditPartViewer.class);
// get Target EditPart that is under the mouse
EditPart targetEditPart = viewer.findObjectAt(getLocation());
// If nothing under mouse, set root item as target (just playing safe)
if(targetEditPart == null)
targetEditPart = viewer.getContents();
// Make and initialize create request with proper information
CreateRequest createReq = new CreateRequest();
createReq.setLocation(getLocation());
createReq.setFactory(new OwnFactoryImplementation());
// Ask from target editpart command for this request
Command command = targetEditPart.getCommand(createReq);
// If command is ok, and it can be executed, go and execute it on commandstack
if(command != null && command.canExecute()) {
viewer.getEditDomain().getCommandStack().execute(command);
}
}
Now what happens is that editpart will be requested for creation, so the action itself doesn't know how the command works, what makes it objective agaist the command.
So to make things work, you need to install new EditPolicy to your EditPart. EditPolicies can be installed on EditParts createDefaultEditPolicies() function. This EditPolicy must react and return command when there is CreateRequest. This way any child can provide own kind of command for creating children for itself.
Here is a good image how it works (controller is EditPart):
Please ask if I can help you some more. I know that this looks bit more complex, but this makes your own life much more easier, and after you have done that, you actually understand Command-Request Pattern quite well, and it can be reused in many different places.

Qt: delegate to a single editor

What im trying to do is have a table which does not appear editable directly but can be edited in some widget outside the table. That is, the selected node can be edited here, and all nodes use the same editor because i want it to always be shown.
What I've tried is to subclass QItemDelegate and just return the instance of QTextEdit i already have, like this:
class Delegate extends QItemDelegate {
#Override
public QWidget createEditor(QWidget parent, QStyleOptionViewItem option, QModelIndex index) {
return qtextEdit;
}
}
which works, except that when you leave the editor it gets destroyed. Maybe delegate isn't supposed to be used this way. So how can i achieve this?
(ps. im using jambi but c++ code is fine)
The QDataWidgetMapper class is exactly what you want, to edit the values of whatever record outside of the view in external controls.
Taken straight from the documentation, this is how you'd use it:
QDataWidgetMapper *mapper = new QDataWidgetMapper;
mapper->setModel(model);
mapper->addMapping(mySpinBox, 0);
mapper->addMapping(myLineEdit, 1);
mapper->addMapping(myCountryChooser, 2);
mapper->toFirst();
And, if you have a view (QTreeView / QListView / QTableView / etc) and you want to edit the currently selected item, connect the appropriate signal & slot:
connect(&view, SIGNAL(activated(QModelIndex)), mapper, SLOT(setCurrentModelIndex(QModelIndex)));

Categories

Resources