Netbeans Platform: how to use a Frame instead of a TopComponent? - java

In my project (with the Netbeans Platform and JavaFX), which is composed by several Tabs (all of them are created subclassing the TopComponent class) I'm trying to implement another tab, which should show the screen of a Virtual Machine already running on VirtualBox.
The problem is that the tool I'm using is composed by a Frame (from Java awt) as top-level container and, naturally, if I try to add it inside my top component I get an exception because it's not possible to include a top-level container inside another top-level container.
So, this is my question: is it possible to create a new component with the NetBeans Platform without using the TopComponent class? I already tried to do that, but the new tab doesn't appear.
#TopComponent.Description(preferredID = "MyTopComponent",
// iconBase="SET/PATH/TO/ICON/HERE",
persistenceType = TopComponent.PERSISTENCE_ALWAYS)
#TopComponent.Registration(mode = "editor", openAtStartup = true)
#ActionReference(path = "Menu/Window" /* , position = 333 */ )
#TopComponent.OpenActionRegistration(displayName = "#CTL_MyAction", preferredID = "MyTopComponent")
public class MyTopComponent extends TopComponent {
/**
* Logging Facility Instance
*/
private static final Logger LOG = LoggerFactory.getLogger(MyTopComponent.class);
private JFXPanel fxPanel;
private RDPClient rdpClient;
private Frame rdpFrame;
public MyTopComponent() {
initTopComponent();
initFXComponent();
setClientProperties();
}
#Override
public void componentClosed() {
// TODO add custom code on component closing
}
private void initTopComponent() {
setName(Bundle.CTL_MyTopComponent());
setToolTipText(Bundle.HINT_MyTopComponent());
}
private void setClientProperties() {
putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, Boolean.TRUE);
putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, Boolean.TRUE);
putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, Boolean.TRUE);
}
private void initFXComponent() {
try {
rdpClient = new RDPClient();
} catch (RdesktopException ex) {
Exceptions.printStackTrace(ex);
}
setLayout(new BorderLayout());
fxPanel = new JFXPanel();
rdpFrame = rdpClient.getComponent();
// fxPanel.add(rdpClient.getComponent());
add(fxPanel, BorderLayout.CENTER);
Platform.setImplicitExit(false);
}
If I try to add the frame inside the JFXPanel it raises an exception. The same happens if I try to add it directly inside the container. Any suggestions?

A Frame, by definition, is a top-level window component. Frames cannot be placed inside another component, other components are placed inside Frames.
If the tool only provides a Frame, it will necessarily be its own window. The only thing you can do with it is set its location, dimensions, show it and hide it, set the title, other framey stuff.

Related

How to make multiple windows in Eclipse RCP e4

We want to achieve an RCP application which may have multiple windows (MWindow)
for distinct data. The Windows must be independent (unlike the Eclipse IDE new
window menu entry), but it must be possible to copy & paste, drag & drop things from
one window into another one. Imagine an application like Word where you can
have multiple documents open. We tried various approaches, but it is quiet
difficult to find out the right e4 way:
1. Creating a new E4Application for each window
Our first approach was to create and run a complete new E4Application for each
new window. But this sounds not to be the right e4 way. Also it is buggy: Key
bindings does not work correct and also the LifecycleManager is called for each new
application and therefor for each new window, which should not be.
E4Application application = new E4Application();
BundleContext context = InternalPlatform.getDefault().getBundleContext();
ServiceReference<?> appContextService = context.getServiceReference(IApplicationContext.class);
IApplicationContext iac = (IApplicationContext) context.getService(appContextService);
IWorkbench workbench = application.createE4Workbench(iac, display);
final E4Workbench implementation = (E4Workbench) workbench;
implementation.createAndRunUI(workbench.getApplication());
This seems not the right approach to do it.
2. The Eclipse IDE approach
In the Eclipse IDE you can go to the menu and click Window -> New Window which
will open a complete new top level window. But it is synchronized: Open the
same text file in both windows and editing it in the first one will alter it in
the other one too. Albeit we tried that approach by simply copy and pasting it
from org.eclipse.ui.actions.OpenInNewWindowAction#run():
// Does not work because we do not have the RCP3 workbench in RCP4.
final IWorkbench workbench = PlatformUI.getWorkbench();
final IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow();
final IWorkbenchPage activePage = workbenchWindow.getActivePage();
final String perspectiveId;
if (activePage != null && activePage.getPerspective() != null) {
perspectiveId = activePage.getPerspective().getId();
} else {
perspectiveId = workbenchWindow.getWorkbench().getPerspectiveRegistry().getDefaultPerspective();
}
workbenchWindow.getWorkbench().openWorkbenchWindow(perspectiveId, null);
It looks like that the Eclipse IDE uses the RCP3 compatibility layer. We didn't
found a way to obtain the IWorkbench object. Neither by
PlatformUI#getWorkbench(), nor via the application context, nor the bundle
context.
3. Clone the main window
We stumbled upon Opening multiple instances of an MTrimmedWindow complete with perspectives etc
n-mtrimmedwindow-complete-with-perspectives-etc and did a lot of trial and
error and came up with this muddy code:
class ElementCloningBasedCreator {
EModelService models = ...; // injected
MApplication app = ...; // injected
public void openNewWindow() {
MWindow originWindow = (MWindow) models.find("the.main.window.id", app);
MWindow newWindow = (MWindow) models.cloneElement(originWindow, null);
MPerspectiveStack newPerspectiveStack =
(MPerspectiveStack) models.find(the.main.perspective.stack.id, newWindow);
newPerspectiveStack.setParent((MElementContainer) newWindow);
addTo(app, newWindow);
// Clone the shared elements. If we don't do that the rendering somewhere
// deep in the rabbit hole throws assertion erros because the recurisve
// finding of an element fails because the search root is null.
for (final MUIElement originSharedElement : originWindow.getSharedElements()) {
final MUIElement clonedSharedElement = models.cloneElement(originSharedElement, null);
clonedSharedElement.setParent((MElementContainer) newWindow);
newWindow.getSharedElements().add(clonedSharedElement);
}
cloneSnippets(app, originWindow, newPerspectiveStack, newWindow);
newWindow.setContext(createContextForNewWindow(originWindow, newWindow));
newWindow.setToBeRendered(true);
newWindow.setVisible(true);
newWindow.setOnTop(true);
models.bringToTop(newWindow);
}
#SuppressWarnings({ "rawtypes", "unchecked" })
private void addTo(MElementContainer target, MUIElement child) {
child.setParent(target);
target.getChildren().add(child);
}
/**
* Clone each snippet that is a perspective and add the cloned perspective
* into the main PerspectiveStack.
*/
private void cloneSnippets(MApplication app, MWindow originWindow,
MPerspectiveStack newPerspectiveStack, MWindow newWindow) {
boolean isFirstSnippet = true;
for (MUIElement snippet : app.getSnippets()) {
if (ignoreSnippet(snippet)) {
continue;
}
String snipetId = snippet.getElementId();
MPerspective clonedPerspective =
(MPerspective) models.cloneSnippet(app, snipetId, originWindow);
findPlaceholdersAndCloneReferencedParts(clonedPerspective, newWindow);
addTo(newPerspectiveStack, clonedPerspective);
if (isFirstSnippet) {
newPerspectiveStack.setSelectedElement(clonedPerspective);
isFirstSnippet = false;
}
}
}
private boolean ignoreSnippet(MUIElement snippet) {
return !(snippet instanceof MPerspective);
}
private void findPlaceholdersAndCloneReferencedParts(MPerspective clonedPerspective, MWindow newWindow) {
List<MPlaceholder> placeholders =
models.findElements(clonedPerspective, null, MPlaceholder.class, null);
for (MPlaceholder placeholder : placeholders) {
MUIElement reference = placeholder.getRef();
if (reference != null) {
placeholder.setRef(models.cloneElement(placeholder.getRef(), null));
placeholder.getRef().setParent((MElementContainer) newWindow);
}
}
}
}
This code does not really work and we really need some hints/advices how to do
it right, because of the lack of official documentation. The questions open are:
Do we need to clone the shared objects and if not how do we prevent the
errors during rendering)?
We only saw code where the cloned elements are
added to the parent via getChildren().add(), but we found out that the
children din't get the parent automatically and it is null though. Is it the
right pattern to add the parent to the child too?
We have the deep feeling
that we are doing it not right. It looks way too complicated what we do here. Is
there a simpler/better approach?
You can use the EModelService cloneSnippet method to do this.
Design your MTrimmedWindow (or whatever type of window you want) in the Snippets section of the Application.e4xmi. Be sure that the To Be Rendered and Visible flags are checked. You may need to set the width and height bounds (and you may want to set the x and y position as well).
Your command handler to create the new window would simply be:
#Execute
public void execute(EModelService modelService, MApplication app)
{
MTrimmedWindow newWin = (MTrimmedWindow)modelService.cloneSnippet(app, "id of the snippet", null);
app.getChildren().add(newWin);
}

Moving JInternalFrames from one JDesktopPane to another

I have been designing a Swing-based tabletop RPG program to facilitate text-based roleplay with GUI control elements.
To facilitate this, each running client gets a main desktop ("GM Desktop" on the hosting client and "Player Desktop" on the remote clients) with all of the important JFrames. Additionally, both GM and Players can open "Perspective Desktops" for characters, providing them with a separate JDesktopPane that contains the "Role Play Chat Window" that gives that character's perspective, along with additional JInternalFrames such as the "Character Sheet Window", etc.
The user navigates between desktops using a JTabbedPane.
The issue that I am having is that SOME of the windows I want to be able to move between desktops. For example, if the OOC (Out-of-Character) Chat receives a message while the user is in a Perspective Desktop, I want there to be an option for the OOC Chat Window to automatically relocate to the current desktop so the user sees the message immediately. Similarly I want the player to be able to "call" certain windows into the current desktop using the menu bar.
However, when I attempt to move a JInternalFrame from one JDesktopPane to another, I receive an exception.
com.finnickslab.textroleplayonline.exceptions.CommandEventHandlingException
An exception was thrown during command handling. CommandEvent type: UI_OOC_CHAT (26).
Cause Exception: java.lang.IllegalArgumentException
illegal component position
java.awt.Container.addImpl(Unknown Source)
javax.swing.JLayeredPane.addImpl(Unknown Source)
javax.swing.JDesktopPane.addImpl(Unknown Source)
java.awt.Container.add(Unknown Source)
com.finnickslab.textroleplayonline.ui.GameDesktop.receiveTransfer(GameDesktop.java:80)
com.finnickslab.textroleplayonline.ui.GameDesktop.access$0(GameDesktop.java:74)
com.finnickslab.textroleplayonline.ui.GameDesktop$2.run(GameDesktop.java:69)
com.finnickslab.textroleplayonline.ui.UI.invokeEvent(UI.java:818)
com.finnickslab.textroleplayonline.ui.GameDesktop.transfer(GameDesktop.java:62)
com.finnickslab.textroleplayonline.ui.UI$HostCommandHandler.handle(UI.java:605)
com.finnickslab.textroleplayonline.comm.Server$3.run(Server.java:324)
All JInternalFrames in my program descend from the same subclass of JInternalFrame ("InternalWindow").
The exception makes it look a little convoluted but it boils down to calling JDesktopPane.remove(JInternalFrame) then JDesktopPane.add(JInternalFrame).
And then I receive that exception as soon as the "add" method is called on GameDesktop line 80.
/**
* Transfers the specified InternalWindow from this GameDesktop to
* the specified GameDesktop. Use this method to prevent
* automatic removal of listeners performed with the
* {#link GameDesktop.remove(InternalWindow)} method.
*/
public synchronized void transfer(
final InternalWindow window,
final GameDesktop gd) {
final GameDesktop desktop = this;
contents.remove(window);
UI.invokeEvent(new Runnable() {
#Override
public void run() {
desktop.remove((JInternalFrame) window);
desktop.validate();
desktop.repaint();
gd.receiveTransfer(window);
}
});
}
private synchronized void receiveTransfer(InternalWindow window) {
contents.add(window);
window.changeDesktop(this);
window.center();
this.add((JInternalFrame) window); // LINE 80
this.validate();
this.repaint();
window.resetPosition();
}
The "UI.invokeEvent(Runnable)" method is a convenience method I wrote for SwingUtilities.invokeAndWait(Runnable). It checks to see if the current thread is the EDT and, if it is, executes the run() method immediately. Otherwise, it uses invokeAndWait(Runnable) to schedule the runnable on the EDT.
Any ideas of how to fix this problem would be appreciated.
EDIT:
All my research on this error suggests that it has something to do with the Z-axis position of the component. I tried changing the add call to specify the z position
super.add(window, getComponentCount());
but no change. Still getting the same IllegalArgumentException.
See if you get the same error when running this. If not, the problem is not with switching the parent of the internal frame, it's with the synchronization.
public class IFSwitch extends JDesktopPane {
final JDesktopPane pane1 = this;
public IFSwitch() {
JFrame frame1 = new JFrame("Frame1");
JFrame frame2 = new JFrame("Frame2");
// JDesktopPane pane1 = new JDesktopPane();
JDesktopPane pane2 = new JDesktopPane();
final JInternalFrame if1 = new JInternalFrame();
frame1.add(pane1);
frame2.add(pane2);
pane1.add(if1);
if1.setBounds(10, 10, 100, 100);
frame1.setBounds(100, 100, 200, 200);
frame2.setBounds(500, 500, 200, 200);
frame1.setVisible(true);
frame2.setVisible(true);
if1.setVisible(true);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
pane2.add(if1);
pane1.remove(if1); // You don't even need this line.
pane1.repaint();
}
public static void main(String[] args) {
new IFSwitch();
}
}

Trying to place an applet as a component using embedded in vaadin 7

Trying to integrate a java applet in my website created using vaadin 7. I am trying to do it using embedded and adding it to the layout. This is what I have right now.
public class DeviceConfigure extends CustomComponent implements View {
#AutoGenerated
private AbsoluteLayout mainLayout;
#AutoGenerated
public DeviceConfigure() {
buildMainLayout();
setCompositionRoot(mainLayout);
Resource res = new ThemeResource("img/stars.jar");
Embedded jarFile = new Embedded("Jar File", res);
mainLayout.addComponent(jarFile);
}
private AbsoluteLayout buildMainLayout() {
// common part: create layout
mainLayout = new AbsoluteLayout();
mainLayout.setImmediate(false);
mainLayout.setWidth("860px");
mainLayout.setHeight("510px");
// top-level component properties
setWidth("860px");
setHeight("510px");
return mainLayout;
}
#Override
public void enter(ViewChangeEvent event) {
// TODO Auto-generated method stub
}
}
I've tried different things like setting the minetype, archive etc.. but can't get it to work. Whenever I navigate to the page the section where the applet should be is just blank. Is there something that I am missing that I'm just not seeing. Thanks to anyone who takes the time to read and reply to this.

only open one JInternalFrame in one time

I've created a Swing application with several JInternalFrames which gets added to a JDesktopPane on the event of a mouse click. I want only one instance of the same Internal frame to be present on the DesktopPane. I dont want the same frame to appear twice when the user opens the frame..
The simple solution to your problem is to create an HashMap<String,JInternalFrame>. The key will be the title of that JInternalFrame and value will be the object of that JInternalframe opened currently.Save the (key,value) pair in HashMap when the internal frame is opened first time. Disable the close button for all JInternalFrame window , so that user can't dispose the displayed JInternalFrame window. Register esc key to each JInternalFrame object , so that when esc button of keyboard is pressed the currently display JInternalFrame is minimized on the DesktopPane.Now When you click on menu item to open that same internal frame, check if the title of that JInternalFrame is existing in that HashMap askey. If it exists then retrieve the value for that key and refer it by JInternalFrame variable and then restore the same on DesktopPane. If the corresponding entry of title doesn't exist in that HashMap , create a new JInternalFrame object, make an entry for same in the HasMap and display it.
Note: Whatever I have posted here is the solution for the situation where
you can have many types of JInternalFrame each having unique
different functionality, and you want to keep only one instance of
each of those JInternalFrame.
Here is may sample code. hope this help.
Menu action to call internal frame in main application where JdesktopPane in it.
private void YourJinternalFrameMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
YourJinternalFrame nw = YourJinternalFrame.getInstance();
nw.pack();
//usefull part for you.. if open shows, if not creates new one
if (nw.isVisible()) {
} else {
desktopPane.add(nw);
nw.setVisible(true);
}
try {
nw.setMaximum(true);
} catch (PropertyVetoException ex) {
Logger.getLogger(MainApplication.class.getName()).log(Level.SEVERE, null, ex);
}
}
put this inside of your YourJinternalFrame
private static YourJinternalFrame myInstance;
public static YourJinternalFrame getInstance() {
if (myInstance == null) {
myInstance = new YourJinternalFrame();
}
return myInstance;
Try this simple code :
YourJinternalFrame nw = new YourJinternalFrame();
private void YourJinternalFrameMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
if(!nw.isVisible()){
YourJDesktopPane.add(nw);
nw.setVisible(true);
}
}
Try this simple code
take class variable chk and set equal to 0
then call jframe method
componentremoved
in this set chk =0 again
and if you call your internal frame set
chk =1
and compare chk on calling internal wheather it is zero or not
thats all
I went for a different solution:
final JInternalFrame[] frames = desktopPane.getAllFrames();
if( !Arrays.asList(frames).contains(loginFrame) ) {
loginFrame = new LoginFrame();
desktopPane.add(loginFrame);
loginFrame.setVisible(true);
}
This worked for me (checking for the class name):
final JInternalFrame[] frames = desktopPane.getAllFrames();
LoginFrame loginFrame = new LoginFrame();
if( !Arrays.asList(frames).toString().contains("LoginFrame") ) {
desktopPane.add(loginFrame);
loginFrame.setVisible(true);
loginFrame.validate();
}

How to Subscribe to GUI Events in Other JFrames

What is the best practice for subscribing to events from another JFrame? For example, I have a "settings" form, and when the user presses okay on the settings form, I want the main form to know about this so it can retrieve the settings.
Thanks.
Here is my ideal interface:
public void showSettingsButton_Click() {
frmSettings sForm = new sForm(this._currentSettings);
//sForm.btnOkay.Click = okayButtonClicked; // What to do here?
sForm.setVisible(true);
}
public void okayButtonClicked(frmSettings sForm) {
this._currentSettings = sForm.getSettings();
}
Someone publishes an Event, that something has changed, here the settings. A subscriber that registered for this specifig event, gets notified about it and can do his work, here get the settings. This is called publisher/subscriber.
For this you can use Eventbus or implementing something smaller on your own.
One approach is to have only a single JFrame. All the other 'free floating top level containers' could be modal dialogs. Access the the main GUI will be blocked until the current dialog is dismissed, and the code in the main frame can check the settings of the dialog after it is dismissed.
For anyone interested, here is what I ended up going with. I'm not sure if it's the best way, but it is working for my purposes.
// Method called when the "Show Settings" button is pressed from the main JFrame
private void showSettingsButton_Click() {
// Create new settings form and populate with my settings
frmSettings sForm = new frmSettings(this.mySettings);
// Get the "Save" button and register for its click event...
JButton btnSave = sForm.getSaveButton();
btnSave.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent evt) {
SaveSettings(sForm);
}
});
// Show the settings form
sForm.setVisible(true);
}
// Method called whenever the save button is clicked on the settings form
private void SaveSettings(frmSettings sForm) {
// Get the new settings and assign them to the local member
Settings newSettings = sForm.getSettings();
this.mySettings = newSettings;
}
And if, like me, you are coming from a .NET perspective, here is the C# version:
private void showSettingsButton_Click(object sender, EventArgs e)
{
frmSettings sForm = new frmSettings(this.mySettings);
sForm.btnSave += new EventHandler(SaveSettings);
sForm.Show();
}
private void SaveSettings(object sender, EventArgs e)
{
frmSettings sForm = (frmSettings)sender; // This isn't the exact cast you need..
Settings newSettings = sForm.Settings;
this.mySettings = newSettings;
}

Categories

Resources