Capture about, preferences and quit menu items - java

I'm using the current version of SWT to build my applications and I want to run it under Mac OS X (Yosemite).
My problem is now that I'm not be able to capture clicks on the "About", "Preferences" and "Quit" menu items which were automatically added to my application.
I already searched a lot and found the following class which seems very helpful to me http://www.transparentech.com/files/CocoaUIEnhancer.java.
And that's my code to initialize it:
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
public class Test {
private Display display;
private Shell shell;
public Test(Display display) {
this.display = display;
initUI();
}
public void open() {
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
private void initUI() {
shell = new Shell(display);
shell.setSize(808, 599);
shell.setText("Test");
AboutHandler aboutHandler = new AboutHandler();
PreferencesHandler preferencesHandler = new PreferencesHandler();
QuitHandler quitHandler = new QuitHandler();
CocoaUIEnhancer uienhancer = new CocoaUIEnhancer("Test");
uienhancer.hookApplicationMenu(display, quitHandler, aboutHandler, preferencesHandler);
}
private class AboutHandler implements Listener {
public void handleEvent(Event e) {
}
}
private class PreferencesHandler implements Listener {
public void handleEvent(Event e) {
}
}
private class QuitHandler implements Listener {
public void handleEvent(Event e) {
}
}
}
I can compile it without any errors but if I start the program then I will get the following exception:
Exception in thread "main" java.lang.NoSuchMethodError: actionProc
at org.eclipse.swt.internal.Callback.bind(Native Method)
at org.eclipse.swt.internal.Callback.<init>(Unknown Source)
at org.eclipse.swt.internal.Callback.<init>(Unknown Source)
at org.eclipse.swt.internal.Callback.<init>(Unknown Source)
at CocoaUIEnhancer.initialize(CocoaUIEnhancer.java:124)
at CocoaUIEnhancer.hookApplicationMenu(CocoaUIEnhancer.java:92)
at Test.initUI(Test.java:50)
at Test.<init>(Test.java:18)
It's probably an error in the native libraries but I can't figure it out!

I didn't use CocoaUIEnhancer at all, as it was causing issues as well.
So here's what I ended up doing in my applications:
/**
* Convenience method that takes care of special menu items (About, Preferences, Quit)
*
* #param name The name of the menu item
* #param parent The parent {#link Menu}
* #param listener The {#link Listener} to add to the item
* #param id The <code>SWT.ID_*</code> id
*/
private void addMenuItem(String name, Menu parent, Listener listener, int id)
{
if (OSUtils.isMac())
{
Menu systemMenu = Display.getDefault().getSystemMenu();
for (MenuItem systemItem : systemMenu.getItems())
{
if (systemItem.getID() == id)
{
systemItem.addListener(SWT.Selection, listener);
return;
}
}
}
/* We get here if we're not running on a Mac, or if we're running on a Mac, but the menu item with the given id hasn't been found */
MenuItem item = new MenuItem(parent, SWT.NONE);
item.setText(name);
item.addListener(SWT.Selection, listener);
}
Just call it with SWT.ID_PREFERENCES, SWT.ID_ABOUT and SWT.ID_QUIT respectively. Hand in a fallback menu item name, a fallback Menu and the actual Listener you want to add to the menu item.
So for example:
addMenuItem("Quit", myMenu, new Listener()
{
#Override
public void handleEvent(Event event)
{
// Close database connection for example
}
}, SWT.ID_QUIT);

It looks like this the actionProc
int actionProc( int id, int sel, int arg0 )
in CocoaUIEnhancer probably needs to use long rather than int for the arguments to work with 64 bit SWT.

You need to modify CocoaUIEnhancer.java, to make it work with pure SWT application as described in this tutorial:
Modify the getProductName() method to return a String when no product is found (instead of null)
Wrap the code in hookWorkbenchListener() in a try-catch (IllegalStateException e) block
Wrap the code in modifyShells() in a try-catch (IllegalStateException e) block
Add some code to the actionProc(...) method, to bring up an About-Dialog and Preferences-Dialog (since we aren’t using commands):
static long actionProc(long id, long sel, long arg0) throws Exception {
// ...
else if (sel == sel_preferencesMenuItemSelected_) {
showPreferences();
} else if (sel == sel_aboutMenuItemSelected_) {
showAbout();
}
return 0;
}
private static void showAbout() {
MessageDialog.openInformation(null, "About...",
"Replace with a proper about text / dialog");
}
private static void showPreferences() {
System.out.println("Preferences...");
PreferenceManager manager = new PreferenceManager();
PreferenceDialog dialog = new PreferenceDialog(null, manager);
dialog.open();
}
// ...
Finally, we add the following lines to our main() method:
public static final String APP_NAME = "MyApp";
public static void main(String[] args) {
//in your case change the Test constructor
Display.setAppName(APP_NAME);
Display display = Display.getDefault();
//insert in initUI method call the earlysetup
if (SWT.getPlatform().equals("cocoa")) {
new CocoaUIEnhancer().earlyStartup();
}
Shell shell = new Shell(display);
shell.setText(APP_NAME);
...
}
Quoted code.

Baz's solution works great! If you'd rather not import OSUtils just to test if you are on a Mac, use instead:
System.getProperty("os.name").contentEquals("Mac OS X")

Related

Editable JComboBox firing ActionListener when losing focus

I am writing a class (UIPromptComboBox) that extends JComboBox. The combobox is editable and for one application of the class it is implemented with a controlling ActionListener.
Currently, when the combobox is edited it fires the ActionListener which is good. However this ActionListener is also fired when I deselect the combobox and I cannot distinguish between the two events nor do I want it to fire when the combobox is deselected.
Implementing Class
private void addUIField() {
// Initialise and place combobox
this.myGuiTextField = new UIPromptComboBox();
myGuiTextField.setSize(COMBO_WIDTH, defaultHeight);
GuiUtils.positionControl(myPanel, myGuiTextField, myTop, PROMPT_X_LOC);
//Add action listener
myGuiTextField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
if (evt.getActionCommand().equals("comboBoxEdited")) {
newUIcreated((UIPromptComboBox) evt.getSource());
}
}
private void newUIcreated(UIPromptComboBox alteredGuiTextField) {
try {
UIPrompt uip = alteredGuiTextField.getUIPrompt(((PowerPointTextItem) myPPTRef).getValue());
if (!simInfo.isInPrompts(uip)) {
simInfo.addUIPrompt(uip);
alteredGuiTextField.addNewUIPrompt(uip);
}
} catch (MissingPowerpointItem ex) {
Exceptions.printStackTrace(ex);
}
}
});
}
Class that extends JComboBox
public class UIPromptComboBox extends JComboBox {
public UIPromptComboBox(UIPrompt[] items) {
super(items);
this.setEditable(true);
}
public UIPromptComboBox() {
this.setEditable(true);
this.setEnabled(false);
}
/**
* returns either the selected UI prompt or a new prompt using the example
* text
*
* #param exampleText only used if new prompt is created
* #return UI prompt selected
*/
public UIPrompt getUIPrompt(String exampleText) {
UIPrompt uIPrompt = null;
Object returnedItem = this.getSelectedItem();
if (returnedItem instanceof UIPrompt) {
uIPrompt = (UIPrompt) returnedItem;
} else if (returnedItem instanceof String) {
uIPrompt = new UIPrompt((String) returnedItem, exampleText);
}
return uIPrompt;
}
public void addNewUIPrompt(UIPrompt newPrompt) {
ActionListener[] actionListerners = this.getActionListeners();
this.removeActionListener(this);
this.addItem(newPrompt);
this.setSelectedItem(newPrompt);
for (ActionListener al : actionListerners) {
this.addActionListener(al);
}
}
/**
* Used for displaying a report value sentence
* i.e. a string that is not associated with UI Prompts
* #param newText report value sentence
*/
public void setText(String newText) {
this.removeAllItems();
this.addItem(newText);
this.setSelectedItem(newText);
}
/**
* For when the UI prompts can be added on construction
*
* #param currentUIs list of UI promts
*/
public void addItems(UIPrompt[] currentUIs) {
this.removeAllItems();
DefaultComboBoxModel boxModel = new DefaultComboBoxModel(currentUIs);
this.setModel(boxModel);
}
}
The multiple firing due to losing focus is causing multiple objects to be created and added to the list. I think I may have implemented the ActionListener incorrectly. Thank you for your help
as you stated you only want the event to fire if the user presses enter. a better way to implement that, would be using an keylistener instead of an action listener.
myGuiTextField.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
newUIcreated((UIPromptComboBox) evt.getSource());
}
}
private void newUIcreated(UIPromptComboBox alteredGuiTextField) {
try {
UIPrompt uip = alteredGuiTextField.getUIPrompt(((PowerPointTextItem) myPPTRef).getValue());
if (!simInfo.isInPrompts(uip)) {
simInfo.addUIPrompt(uip);
alteredGuiTextField.addNewUIPrompt(uip);
}
} catch (MissingPowerpointItem ex) {
Exceptions.printStackTrace(ex);
}
}
});
this should now only fire your event newUIcreated, once the users presses enter and at no other time. replace your action listener with this
I have now finally found the issue.
The displaying of the UIPrompt included the addition of a string that sometimes contained a new line character.
The action of clicking another field was triggering the render of the UIPrompt however when this contained a newline character it was triggering the ActionListener again. This what the reason for the repeated action of comboBoxEdited.

Java Intermec ITCScan failed to load

I'm trying to implement a Barcode Reader for a CK71 ATEX Intermec Scanner. The operating system is Windows Embedded Handheld 6.5 and as JVM I'm using phoneME Personal Profile. I did install the DC_Java_WM6_Armv4i.cab (see the picture)
When I run the code below I get the following error: ITCScan failed to load. java.lang.UnsatisfiedLinkError: no ITCScan.dll in java.library.path
How can I fix this error? I've tried everything.
Note that before, I was using CreME JVM and everything was working fine. I gave up CreME when my 30 days evaluation version expired.
The content of the .lnk file (instead of myProject.MainClass are the real names of course):
255#"\Program Files\pMEA PP\bin\cvm.exe" "-Xopt:stdioPrefix=\My Documents,useConsole=false" -cp "\My Documents\Trasabilitate.jar;\My Documents\DataCollection.jar" myProject.MainClass
Here is the complete code:
/*
* BarcodeSample.java
*
* COPYRIGHT (c) 2004 INTERMEC TECHNOLOGIES CORPORATION, ALL RIGHTS RESERVED
*/
import java.awt.*;
import com.intermec.datacollection.*;
/**
* This sample demonstrates using the BarcodeReader class to
* read barcode data into a text field.
*/
public class BarcodeSample extends Frame implements BarcodeReadListener
{
BarcodeReader bcRdr;
TextField txtFieldData;
Button btnClose;
Label labelStatus;
public BarcodeSample(String aTitle)
{
super(aTitle);
initComponents();
try
{
bcRdr = new BarcodeReader();
bcRdr.addBarcodeReadListener(this);
// Starts asynchronous barcode read
bcRdr.threadedRead(true);
}
catch (BarcodeReaderException e)
{
System.out.println(e);
labelStatus.setText(e.getMessage());
//*****
//* Since m_labelStatus was not initialized with text,
//* doLayout() is required on some platforms in order
//* to show the new label text for the first setText()
//* call.
//*****
doLayout();
}
}
private void initComponents()
{
setLayout(new FlowLayout());
txtFieldData = new TextField(20);
add(txtFieldData);
btnClose = new Button("Close");
add(btnClose);
labelStatus = new Label();
add(labelStatus);
btnClose.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent e)
{
exitApp();
}
});
btnClose.addKeyListener(new java.awt.event.KeyListener() {
public void keyPressed(java.awt.event.KeyEvent e) {
if (e.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER)
{
exitApp();
}
}
public void keyReleased(java.awt.event.KeyEvent e) {}
public void keyTyped(java.awt.event.KeyEvent e) {}
});
}
/**
* This method is invoked when the BarcodeReadEvent occurs.
*/
public void barcodeRead(BarcodeReadEvent aBarcodeReadEvent)
{
/**
* Uses EventQueue.invokeLater to ensure the UI update
* executes on the AWT event dispatching thread.
*/
final String sNewData = aBarcodeReadEvent.strDataBuffer;
EventQueue.invokeLater(new Runnable() {
public void run() {
// Displays the scanned data in the text field
txtFieldData.setText(sNewData);
}
});
}
public void exitApp()
{
if (bcRdr != null)
bcRdr.dispose(); // Release system resources used by BarcodeReader
setVisible(false);
dispose(); // Dispose the frame
System.exit(0);
}
public static void main(String[] args)
{
final BarcodeSample asyncReader =
new BarcodeSample("Barcode Sample");
asyncReader.addWindowListener(new java.awt.event.WindowAdapter()
{
public void windowClosing(java.awt.event.WindowEvent e)
{
asyncReader.exitApp();
};
});
asyncReader.setVisible(true);
}
}
I finally got it to work. I found out what my java path was using the snippet here (I'll post it below in case something happens to the link):
Properties p = System.getProperties();
Enumeration keys = p.keys();
while (keys.hasMoreElements()) {
String key = (String)keys.nextElement();
String value = (String)p.get(key);
System.out.println(key + ": " + value);
}
And then I added my ITCScan.dll to the folder where java.library.path was set (in my case, \ProgramFiles\pMEA PP\bin.
I don't know if this is the most elegant solution, but it works. Hope it'll help somebody someday.

Java SWT - Creating a new window from other class

Today I wanted to create a simple Java SWT GUI Application using Eclipse, but for better clarity I wanted to have every sub-window in a different class. Since I am very new to Java Programming, is there a way to make a different class do its thing just by calling a method? I looked everywhere on the internet, but couldn't find what I was looking for...
Here's what I have so far
Button foo = new Button(shell, SWT.PUSH);
foo.setText("Edit");
foo.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
switch (e.type) {
case SWT.Selection:
// Call the other Class file here
break;
}
}
});
Yes. It is possible. I wouldn't call it "calling a class" though, rather "opening another window" in SWT terms.
You simply wrap a Shell in your other class, then call the open() API from "outside".
If you want to edit something, you could even create wizards.
There are many ways to do what you want to do, I simply chose one of the simple versions. But this is not the only way to do it. Wait for Baz to answer, he'll come along with another cool example. ;)
I would recommend you read the Shell's javadoc, too.
Example:
ShellTest.class (run this as Java Application)
/**
*
* #author ggrec
*
*/
public class ShellTest
{
// ==================== 2. Instance Fields ============================
private AnotherShell anotherShell;
// ==================== 3. Static Methods =============================
public static void main(final String[] args)
{
new ShellTest();
}
// ==================== 4. Constructors ===============================
private ShellTest()
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
anotherShell = new AnotherShell();
createContents(shell);
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if ( !display.readAndDispatch() )
display.sleep();
}
display.dispose();
}
// ==================== 5. Creators ===================================
private void createContents(final Composite parent)
{
final Button buttonOpen = new Button(parent, SWT.PUSH);
buttonOpen.setText("Open");
buttonOpen.addSelectionListener(new SelectionAdapter()
{
#Override public void widgetSelected(final SelectionEvent e)
{
anotherShell.open();
}
});
final Button buttonClose = new Button(parent, SWT.PUSH);
buttonClose.setText("Close");
buttonClose.addSelectionListener(new SelectionAdapter()
{
#Override public void widgetSelected(final SelectionEvent e)
{
anotherShell.close();
}
});
}
}
AnotherShell.class (this would be your "other class")
/**
*
* #author ggrec
*
*/
public class AnotherShell
{
// ==================== 2. Instance Fields ============================
private Shell shell;
// ==================== 4. Constructors ===============================
public AnotherShell()
{
shell = new Shell(Display.getCurrent());
}
// ==================== 6. Action Methods =============================
public void open()
{
shell.open();
}
public void close()
{
// Don't call shell.close(), because then
// you'll have to re-create it
shell.setVisible(false);
}
}

SWT - Inheriting parent dialog shell?

I am really needing to understand how parent/child dialogs work.
My users use a OTB Application called Teamcenter. I am writing a add on application that is invoked from a menu selection in the Teamcenter Application.
When they click the menu item, that executes a handler class and that creates the base dialog for my application.
public class AplotDialogHandler extends AbstractHandler {
private static AplotBaseDialog dlg = null;
public AplotDialogHandler() {
}// end Constructor
//////////////////////////////////////////////////////////////////////////
// execute() //
//////////////////////////////////////////////////////////////////////////
#Override
public Object execute(final ExecutionEvent event) throws ExecutionException {
if (dlg == null) {
try {
AbstractAIFApplication app = AIFDesktop.getActiveDesktop().getCurrentApplication();
TCSession session = (TCSession) app.getSession();
TCUserService userService = session.getUserService();
AplotVersion.negotiateVersion(userService);
AplotQueryCapabilities.initialize(userService);
dlg = new AplotBaseDialog(null, session);
}
catch (Exception ex) {
MessageBox.post(HandlerUtil.getActiveWorkbenchWindowChecked(event).getShell(), ex, true);
}
}
dlg.create();
dlg.getShell().setSize(700, 400);
dlg.open();
return null;
}// end execute()
}// end EdiDialogHandler()
Question 1. It seems like my application is not tied to the Teamcenter application. Meaning that I can close Teamcenter and my Application stays open.
Question 2. Should I get the workspace shell and pass it in the base dialog?
But even when my application is open, the user still needs to be able to use the Teamcenter application to select data to send to my application
Question 3. When opening dialogs from my base dialog, should I always pass the base dialog shell to those dialogs?
Question 4. Is there a standard way I should close down the dialogs when the user is done?
You need to pass the parent Shell to the dialog so that when you close parent shell, child shells will also be closed.
You should make your dialog MODELESS ( use SWT.MODELSS as style. Note: it is Hint) so that it will not block your parent shell.
Here is sample code:
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
shell.setSize(200, 200);
Button b = new Button(shell, SWT.NONE);
b.setText("Click");
b.addSelectionListener(new SelectionListener() {
#Override
public void widgetSelected(SelectionEvent e) {
CDialog dialog = new CDialog(shell);
dialog.open();
}
#Override
public void widgetDefaultSelected(SelectionEvent e) {
// TODO Auto-generated method stub
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private static class CDialog extends Dialog
{
/**
* #param parentShell
*/
protected CDialog(Shell parentShell) {
super(parentShell);
}
/* (non-Javadoc)
* #see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
*/
#Override
protected Control createDialogArea(Composite parent) {
Composite comp = (Composite) super.createDialogArea(parent);
Label lbl = new Label(comp, SWT.NONE);
lbl.setText("Test modeless dialog");
return comp;
}
/* (non-Javadoc)
* #see org.eclipse.jface.window.Window#getShellStyle()
*/
#Override
protected int getShellStyle() {
return SWT.DIALOG_TRIM|SWT.MODELESS;
}
}

Handle the closing of the workbench window in Java RCP application

I'm writing an Eclipse RCP and I want to ask the user whether to backup the database when the application is closed. Doing it from the File>Exit menu was easy as I defined a command exit:
public class ExitCommand extends AbstractHandler implements IHandler {
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
final IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench == null)
return null;
// Ask whether the user wants to back up the information
Shell shell = new Shell(workbench.getDisplay());
MessageBox messageBox = new MessageBox(shell, SWT.ICON_QUESTION
| SWT.YES | SWT.NO);
messageBox.setMessage("You are leaving CatSysPD. Do you want to make a backup of the DataBase? (recommended)");
messageBox.setText("On Exit Backup");
int response = messageBox.open();
if (response == SWT.YES){
new BackupDataBaseAction(shell);
}
final Display display = workbench.getDisplay();
display.syncExec(new Runnable() {
public void run() {
if (!display.isDisposed())
workbench.close();
}
});
return null;
}}
I then linked this to a menu entry called Exit and this work right. However the user could close the application also by pressing the "close window" button. Is there any way of catching this event?
I found a suggestion in a previous topic (see here) using a shutdownHook. However the thread that I want execute has to open a dialog and, as I understand, this cannot be done by an external thread.
Thank you!
Edit
I add here the code for the shutdownHook I'm using. In the Application class:
public class Application implements IApplication {
final double NIDAQmxPortingVersionDependency = 1.001;
public final static String PLUGIN_ID = "CatsysPD";
private static Logger logger = Logger.getLogger(Application.class
.toString());
/*
* (non-Javadoc)
*
* #see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.
* IApplicationContext)
*/
public Object start(IApplicationContext context) {
logger.info("Starting the application");
Display display = PlatformUI.createDisplay();
systemCheck(display);
initializeApplication(display);
try {
int returnCode = PlatformUI.createAndRunWorkbench(display,
new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART) {
return IApplication.EXIT_RESTART;
}
BackupOnExitHook backupOnExitHook = new BackupOnExitHook(PlatformUI.getWorkbench().getDisplay());
Runtime.getRuntime().addShutdownHook(backupOnExitHook);
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}
private void systemCheck(Display display) {...}
public void stop() {...}
public void initializeApplication(Display display) {...}
private class BackupOnExitHook extends Thread {
private Display display;
public BackupOnExitHook(Display display){
this.display = display;
}
#Override
public void run(){
display.syncExec(new Runnable(){
#Override
public void run() {
MessageBox messageBox = new MessageBox(new Shell(display), SWT.ICON_QUESTION
| SWT.YES | SWT.NO);
messageBox.setMessage("You are leaving CatSysPD. Do you want to make a backup of the DataBase? (recommended)");
messageBox.setText("On Exit Backup");
int response = messageBox.open();
if (response == SWT.YES){
new BackupDataBaseAction(new Shell(display));
}
}});
}
}
}
The error I get when I try to run it is:
Exception in thread "Thread-5" org.eclipse.swt.SWTException: Device is disposed
at org.eclipse.swt.SWT.error(SWT.java:4083)
at org.eclipse.swt.SWT.error(SWT.java:3998)
at org.eclipse.swt.SWT.error(SWT.java:3969)
at org.eclipse.swt.widgets.Display.error(Display.java:1249)
at org.eclipse.swt.widgets.Display.syncExec(Display.java:4581)
at dk.catsys.pd.Application$BackupOnExitHook.run(Application.java:128)
Thanks again.
How about preWindowShellClose from WorkbenchWIndowAdvisor?
http://help.eclipse.org/helios/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/ui/application/WorkbenchWindowAdvisor.html

Categories