OpenDatabaseDialog.java

Go to the documentation of this file.
00001 package edu.rice.cs.hpc.traceviewer.ui;
00002 
00003 import org.eclipse.jface.action.IStatusLineManager;
00004 import org.eclipse.jface.dialogs.Dialog;
00005 import org.eclipse.jface.dialogs.IDialogConstants;
00006 import org.eclipse.jface.dialogs.MessageDialog;
00007 import org.eclipse.jface.layout.GridDataFactory;
00008 import org.eclipse.jface.layout.GridLayoutFactory;
00009 import org.eclipse.swt.SWT;
00010 import org.eclipse.swt.events.ModifyEvent;
00011 import org.eclipse.swt.events.ModifyListener;
00012 import org.eclipse.swt.events.SelectionEvent;
00013 import org.eclipse.swt.events.SelectionListener;
00014 import org.eclipse.swt.layout.FillLayout;
00015 import org.eclipse.swt.widgets.Button;
00016 import org.eclipse.swt.widgets.Combo;
00017 import org.eclipse.swt.widgets.Composite;
00018 import org.eclipse.swt.widgets.Control;
00019 import org.eclipse.swt.widgets.DirectoryDialog;
00020 import org.eclipse.swt.widgets.Display;
00021 import org.eclipse.swt.widgets.Group;
00022 import org.eclipse.swt.widgets.Label;
00023 import org.eclipse.swt.widgets.Shell;
00024 import org.eclipse.swt.widgets.TabFolder;
00025 import org.eclipse.swt.widgets.TabItem;
00026 import org.eclipse.ui.preferences.ScopedPreferenceStore;
00027 
00028 import edu.rice.cs.hpc.common.util.UserInputHistory;
00029 import edu.rice.cs.hpc.traceviewer.db.AbstractDBOpener;
00030 import edu.rice.cs.hpc.traceviewer.db.DatabaseAccessInfo;
00031 import edu.rice.cs.hpc.traceviewer.db.TraceDatabase;
00032 import edu.rice.cs.hpc.traceviewer.db.local.LocalDBOpener;
00033 import edu.rice.cs.hpc.traceviewer.db.remote.RemoteDBOpener;
00034 import edu.rice.cs.hpc.traceviewer.framework.Activator;
00035 
00036 /*******************************************************
00037  * 
00038  * Generic dialog window to open database both locally and remotely
00039  * 
00040  * @author Brett Gutstein, Philip Taffet (original)
00041  * @author Laksono (maintainer)
00042  *******************************************************/
00043 public class OpenDatabaseDialog extends Dialog 
00044 {
00045     // ----------------------------------------------------------------
00046     // constants
00047     // ----------------------------------------------------------------
00048 
00049     private static final String SERVER_NAME_KEY = "server_name";
00050     private static final String SERVER_PORT_KEY = "server_port";
00051     private static final String SERVER_PATH_KEY = "server_path";
00052 
00053     private static final String SERVER_LOGIN = "server_login";
00054     private static final String SERVER_TUNNEL = "server_tunnel";
00055 
00056     private static final String DATABASE_PATH = "database_path";
00057 
00058     private static final String PORT_KEY_DEFAULT = "21590";
00059     private static final String HISTORY_SELECTION = "traceviewer.data.select";
00060 
00061     private static final int NUM_COMBO_FIELDS = 5;
00062     
00063     private final Combo[] comboBoxes = new Combo[NUM_COMBO_FIELDS];
00064 
00065     //Index 0 = Server's name/address; Index 1 = Port; Index 2 = Path to database folder on server
00066     final static int FieldServerName = 0, FieldPortKey = 1, FieldPathKey = 2, FieldServerLogin = 4;
00067     public final static int FieldDatabasePath = 3;
00068 
00069     // ----------------------------------------------------------------
00070     // variables
00071     // ----------------------------------------------------------------
00072 
00073     //This is the most convenient and flexible way to pass around the data.
00074     private String[]  args  = null;
00075     
00076     private final IStatusLineManager status;
00077     private Button okButton;
00078     private String errorMessage;//empty string means no error
00079     private Button checkboxTunneling;
00080 
00081     private UserInputHistory objHistoryName, objHistoryPort, objHistoryPath,
00082     objHistoryDb;
00083     private UserInputHistory objHistoryLoginHost, objHistoryTunnel;
00084 
00085     private TabFolder tabFolder ;
00086 
00087     // the choice is either 
00088     private boolean useLocalDatabase = true;
00089 
00090 
00091     /*****
00092      * constructor with the default error message
00093      * 
00094      * @param parentShell
00095      * @param inStatus
00096      */
00097     public OpenDatabaseDialog(Shell parentShell, final IStatusLineManager inStatus) { 
00098         super(parentShell);
00099         status=inStatus;
00100         errorMessage="";
00101     }
00102 
00103     /*****
00104      * constructor with a customized error message
00105      * 
00106      * @param parentShell
00107      * @param inStatus
00108      * @param error message
00109      */
00110     public OpenDatabaseDialog(Shell parentShell, final IStatusLineManager inStatus, String _errorMessage){
00111         super(parentShell);
00112         status=inStatus;
00113         setErrorMessage(_errorMessage);
00114     }
00115     
00116     public void setErrorMessage(String errorMessage)
00117     {
00118         this.errorMessage = errorMessage;
00119     }
00120     
00121     
00122 
00132     public AbstractDBOpener getDBOpener() {
00133 
00134         if (isLocalDatabase()) {
00135             return new LocalDBOpener(args[FieldDatabasePath]);
00136         } else {
00137             final DatabaseAccessInfo info = new DatabaseAccessInfo();
00138 
00139             info.databasePath = args[FieldPathKey];
00140             info.serverName         = args[FieldServerName];
00141             info.serverPort         = args[FieldPortKey];
00142             info.sshTunnelHostname  = getLoginHost();
00143             info.sshTunnelUsername  = getLoginUser();
00144 
00145             return (isLocalDatabase() ? new LocalDBOpener(args[FieldDatabasePath]) : new RemoteDBOpener(info));
00146         }
00147     }
00148     
00149 
00150     /******
00151      * Return the information to access the database (if the user clicks Ok).
00152      * This information will be needed by {@link TraceDatabasee} to start loading the database
00153      * whether it's local or remote
00154      * 
00155      * @return {@link DatabaseAccessInfo} the information to access the database if okay button is clicked,
00156      *          null otherwise
00157      */
00158     public DatabaseAccessInfo getDatabaseAccessInfo()
00159     {
00160         // no info if the user click cancel button
00161         if (args == null)
00162             return null;
00163         
00164         DatabaseAccessInfo info = new DatabaseAccessInfo();
00165         
00166         if (isLocalDatabase())
00167         {
00168             info.databasePath = args[FieldDatabasePath];
00169         } else 
00170         {
00171             info.databasePath       = args[FieldPathKey];
00172             info.serverName         = args[FieldServerName];
00173             info.serverPort         = args[FieldPortKey];
00174             info.sshTunnelHostname  = getLoginHost();
00175             info.sshTunnelUsername  = getLoginUser();
00176         }
00177         
00178         return info;
00179     }
00180 
00181     //overridden to get ID of the ok button
00182     @Override
00183     protected void createButtonsForButtonBar(Composite parent){
00184         super.createButtonsForButtonBar(parent);
00185         okButton=getButton(IDialogConstants.OK_ID);
00186     }
00187 
00188     @Override
00189     protected Control createDialogArea(Composite parent) {
00190 
00191         getShell().setText("Open a Database");
00192 
00193         if (status != null)
00194             status.setMessage("Select a local or remote directory containing traces");
00195 
00196         Composite outerComposite = (Composite) super.createDialogArea(parent);
00197 
00198         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(outerComposite);
00199         GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(outerComposite);
00200 
00201         tabFolder = new TabFolder(outerComposite, SWT.TOP);
00202 
00203         //add listener to TabFolder to see when ok button can be pressed
00204         tabFolder.addSelectionListener(new SelectionListener() {
00205             @Override
00206             public void widgetDefaultSelected(SelectionEvent e) {}//we dont need to do anything when default selection is made
00207 
00208             @Override
00209             public void widgetSelected(SelectionEvent e) {
00210                 if (okButton != null)
00211                     checkFields();
00212             }
00213         });
00214 
00215         // ----------------------------------------------------- 
00216         // local database
00217         // ----------------------------------------------------- 
00218         TabItem tabLocalItem = new TabItem(tabFolder, SWT.NULL);
00219         tabLocalItem.setText("Local database");
00220 
00221         Composite localComposite = new Composite(tabLocalItem.getParent(), SWT.BORDER_SOLID);
00222         GridLayoutFactory.fillDefaults().numColumns(2).applyTo(localComposite);
00223         GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(localComposite);
00224 
00225         final Label lblBrowse = new Label(localComposite, SWT.LEFT | SWT.WRAP);
00226         lblBrowse.setText("Database:");
00227         GridDataFactory.swtDefaults().grab(false, false).align(SWT.BEGINNING, SWT.CENTER).applyTo(lblBrowse);
00228 
00229         objHistoryDb = new UserInputHistory(DATABASE_PATH);
00230         comboBoxes[FieldDatabasePath] = new Combo(localComposite, SWT.DROP_DOWN | SWT.SINGLE);
00231         setComboWithHistory(comboBoxes[FieldDatabasePath], objHistoryDb, "", 400,
00232                 "Enter the path to the folder containing the database");
00233 
00234         GridDataFactory.fillDefaults().grab(true, false).hint(400, 40).
00235         align(SWT.FILL, SWT.CENTER).applyTo(comboBoxes[FieldDatabasePath]);
00236 
00237 
00238         //directory combo listener to determine when OK can be pressed
00239         ModifyListener localModify = new ModifyListener() {
00240             @Override
00241             public void modifyText(ModifyEvent e) {
00242                 checkFields();
00243             }
00244         };
00245         comboBoxes[FieldDatabasePath].addModifyListener(localModify);
00246 
00247         final Button btnBrowse = new Button(localComposite, SWT.PUSH);
00248         btnBrowse.setText("Browse");
00249 
00250         //browse button listener
00251         btnBrowse.addSelectionListener(new SelectionListener() {
00252 
00253             @Override
00254             public void widgetSelected(SelectionEvent e) {
00255                 DirectoryDialog dialog;
00256 
00257                 dialog = new DirectoryDialog(getShell());
00258                 dialog.setMessage("Please select a directory containing execution traces.");
00259                 dialog.setText("Select Data Directory");
00260 
00261                 final String database = dialog.open();
00262 
00263                 if (database == null)
00264                     // user click cancel
00265                     return;
00266                 comboBoxes[FieldDatabasePath].setText(database);
00267 
00268                 // automatically close the dialog box
00269                 OpenDatabaseDialog.this.okPressed();
00270             }
00271 
00272             @Override
00273             public void widgetDefaultSelected(SelectionEvent e) {}
00274         });
00275 
00276         localComposite.pack();
00277 
00278         tabLocalItem.setControl(localComposite);
00279 
00280         // ----------------------------------------------------- 
00281         // remote database
00282         // ----------------------------------------------------- 
00283         TabItem tabRemoteItem = new TabItem(tabFolder, SWT.NULL);
00284         tabRemoteItem.setText("Remote database");
00285 
00286         Composite remoteComposite = new Composite(tabRemoteItem.getParent(), SWT.NULL);
00287         GridLayoutFactory.fillDefaults().numColumns(2).applyTo(remoteComposite);
00288         GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(remoteComposite);
00289 
00290         //-------- server name
00291         Label serverAddr = new Label(remoteComposite, SWT.LEAD);
00292         serverAddr.setText("Server's host:");
00293 
00294         final Combo name = new Combo(remoteComposite, SWT.SINGLE);       
00295         objHistoryName = new UserInputHistory( SERVER_NAME_KEY );
00296         setComboWithHistory(name, objHistoryName, "", 50,
00297                 "Enter the domain name or IP address of the server to use");
00298 
00299         GridDataFactory.fillDefaults().grab(true, false).applyTo(name);
00300 
00301         comboBoxes[FieldServerName] = name;
00302 
00303         //-------- remote server port       
00304         Label serverPort = new Label(remoteComposite, SWT.LEFT);
00305         serverPort.setText("Port:");
00306         Combo port = new Combo(remoteComposite, SWT.SINGLE);  
00307         objHistoryPort = new UserInputHistory( SERVER_PORT_KEY );
00308 
00309         setComboWithHistory(port, objHistoryPort, PORT_KEY_DEFAULT, 5, 
00310                 "Enter the port to use");
00311 
00312         GridDataFactory.fillDefaults().grab(true, false).applyTo(port);
00313 
00314         comboBoxes[FieldPortKey] = port;
00315 
00316         //-------- remote database path
00317 
00318         Label serverPath = new Label(remoteComposite, SWT.LEAD);
00319         serverPath.setText("Path to database folder:");
00320 
00321         Combo path = new Combo(remoteComposite, SWT.SINGLE);  
00322         objHistoryPath = new UserInputHistory( SERVER_PATH_KEY );
00323         setComboWithHistory(path, objHistoryPath, "", 400, 
00324                 "Enter the path to the folder containing the database on the server");
00325 
00326         GridDataFactory.fillDefaults().grab(true, false).applyTo(path);
00327 
00328         comboBoxes[FieldPathKey] = path;
00329 
00330         //listener used for all three text fields to determine when ok can be pressed
00331         ModifyListener remoteModify = new ModifyListener() {
00332             @Override
00333             public void modifyText(ModifyEvent e) {
00334                 checkFields();
00335             }
00336         };
00337 
00338         //-------- ssh tunneling
00339 
00340         final Group grpTunnel = new Group(remoteComposite, SWT.None);
00341         grpTunnel.setText("SSH Tunneling");
00342         GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(grpTunnel);
00343         GridLayoutFactory.fillDefaults().numColumns(2).applyTo(grpTunnel);
00344 
00345         objHistoryTunnel  = new UserInputHistory(SERVER_TUNNEL, 1);
00346         
00347         checkboxTunneling = new Button(grpTunnel, SWT.CHECK);
00348         checkboxTunneling.setText("Use SSH tunnel (similar to ssh -L port:server_address:port login@hostname)");
00349         boolean check = false;
00350 
00351         String []tunnels = objHistoryTunnel.getHistory();
00352         if (tunnels != null && tunnels.length > 0) {
00353             check = tunnels[0].equals(Boolean.TRUE.toString());
00354         }
00355         checkboxTunneling.setSelection(check);
00356         
00357         GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(checkboxTunneling);
00358         
00359         final Label lblHost = new Label(grpTunnel, SWT.LEFT);
00360         lblHost.setText("login@hostname:");
00361 
00362         objHistoryLoginHost = new UserInputHistory(SERVER_LOGIN);
00363         final Combo login = new Combo(grpTunnel, SWT.SINGLE);
00364         setComboWithHistory(login, objHistoryLoginHost, "login@hostname", 400, 
00365                 "Enter the login and the host for tunneling in format login@hostname");
00366         
00367         GridDataFactory.fillDefaults().grab(true, false).applyTo(login);
00368         login.setEnabled(check); 
00369         comboBoxes[FieldServerLogin] = login;
00370 
00371         checkboxTunneling.addSelectionListener( new SelectionListener() {
00372 
00373             @Override
00374             public void widgetSelected(SelectionEvent e) {
00375                 login.setEnabled(checkboxTunneling.getSelection()); 
00376             }
00377 
00378             @Override
00379             public void widgetDefaultSelected(SelectionEvent e) {}
00380             
00381         });
00382         
00383         // -------------------------------------------
00384         // add listener to all three fields
00385         // -------------------------------------------
00386         name.addModifyListener(remoteModify);
00387         port.addModifyListener(remoteModify);
00388         path.addModifyListener(remoteModify);
00389 
00390         remoteComposite.pack();
00391 
00392         tabRemoteItem.setControl(remoteComposite);
00393 
00394         //add error message if one exists
00395         final Label lblError = new Label(outerComposite, SWT.CENTER | SWT.WRAP);
00396         lblError.setForeground(getShell().getDisplay().getSystemColor(SWT.COLOR_RED));
00397 
00398         if (errorMessage != null)
00399         {
00400             lblError.setText(errorMessage);
00401         }
00402         GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, SWT.DEFAULT).align(SWT.FILL, SWT.CENTER).applyTo(lblError);
00403         getShell().layout(true,true);
00404 
00405         outerComposite.pack();
00406 
00407         // default selection ?
00408         Activator activator = Activator.getDefault();
00409         if (activator != null) {
00410             ScopedPreferenceStore objPref = (ScopedPreferenceStore) activator.getPreferenceStore();
00411             int select = objPref.getInt(HISTORY_SELECTION);
00412             tabFolder.setSelection(select);
00413         }
00414 
00415         return outerComposite;
00416     }
00417 
00418     /*********
00419      * return the username for SSH tunneling
00420      * 
00421      * @return
00422      */
00423     private String getLoginUser()
00424     {
00425         if (args[FieldServerLogin] != null)
00426         {
00427             final String field = args[FieldServerLogin]; 
00428             final String user = field.substring(0, field.indexOf('@'));
00429             return user;
00430         }
00431         return null;
00432     }
00433 
00434     /******
00435      * return the hostname for SSH tunneling
00436      * 
00437      * @return
00438      */
00439     private String getLoginHost()
00440     {
00441         if (args[FieldServerLogin] != null)
00442         {
00443             final String field = args[FieldServerLogin]; 
00444             final String host  = field.substring(field.indexOf('@')+1);
00445             return host;
00446         }
00447         return null;
00448     }
00449 
00450 
00451     private boolean isLocalDatabase()
00452     {
00453         return useLocalDatabase;
00454     }
00455 
00456 
00457     /*******
00458      * Automatically fill the combo with the user's previous entries (based on history) 
00459      * 
00460      * @param combo
00461      * @param history
00462      * @param defaultValue
00463      * @param limit
00464      * @param tooltipText
00465      */
00466     private void setComboWithHistory(Combo combo, UserInputHistory history, String defaultValue,
00467             int limit, String tooltipText)
00468     {
00469         final String []logs = history.getHistory();
00470         if (logs != null && logs.length > 0)
00471         {
00472             combo.setItems(logs);
00473             combo.select(0);
00474         }
00475         else 
00476         {
00477             combo.setText(defaultValue);
00478         }
00479         combo.setTextLimit(limit);
00480         combo.setToolTipText(tooltipText); 
00481     }
00482 
00483 
00484     @Override
00485     /*
00486      * (non-Javadoc)
00487      * @see org.eclipse.jface.dialogs.Dialog#okPressed()
00488      */
00489     protected void okPressed() {
00490 
00491         args = new String[NUM_COMBO_FIELDS];
00492         useLocalDatabase = tabFolder.getSelectionIndex() == 0;
00493 
00494         if (useLocalDatabase)
00495         {
00496             final String filename   = comboBoxes[FieldDatabasePath].getText();
00497             args[FieldDatabasePath] = filename;
00498             objHistoryDb.addLine(filename);
00499         } else
00500         {
00501             // ------------------------------------
00502             // testing the input's validity
00503             // ------------------------------------
00504             final String login = comboBoxes[FieldServerLogin].getText(); 
00505             if (!login.isEmpty())
00506             {
00507                 if (login.indexOf( '@' ) < 0) {
00508                     MessageDialog.openError(getShell(), "Invalid input", "The SSH tunnel login input is invalid");
00509                     return;
00510                 }
00511             }
00512             
00513             try{
00514                 Integer portVal = (Integer.valueOf(comboBoxes[FieldPortKey].getText()));
00515                 args[FieldPortKey] = portVal.toString().trim();
00516             }
00517             catch (NumberFormatException r) //if this exception is thrown the dialog box is not submitted and the user must re-enter a port with numbers only
00518             {
00519                 comboBoxes[FieldPortKey].setText("");
00520                 return;
00521             }
00522 
00523             args[FieldServerName]  = comboBoxes[FieldServerName].getText();
00524             args[FieldPathKey]     = comboBoxes[FieldPathKey].getText();
00525             
00526             if (checkboxTunneling.getSelection()) {
00527                 args[FieldServerLogin] = comboBoxes[FieldServerLogin].getText();
00528                 objHistoryLoginHost.addLine(args[FieldServerLogin]);
00529             } else {
00530                 args[FieldServerLogin] = null;
00531             }
00532 
00533             // ------------------------------------
00534             // save the history to the user preferences
00535             // ------------------------------------
00536             objHistoryName.addLine(args[FieldServerName]);
00537             objHistoryPort.addLine(args[FieldPortKey]);
00538             objHistoryPath.addLine(args[FieldPathKey]);
00539             objHistoryTunnel.addLine(String.valueOf( checkboxTunneling.getSelection()) );
00540         }
00541 
00542         Activator activator = Activator.getDefault();
00543         if (activator != null) {
00544             ScopedPreferenceStore objPref = (ScopedPreferenceStore) activator.getPreferenceStore();
00545             objPref.setValue(HISTORY_SELECTION, tabFolder.getSelectionIndex());
00546         }
00547 
00548         super.okPressed();
00549     }
00550 
00551     /****
00552      * check combo boxes fields in local and remote tab
00553      * If the field is not empty, we enable OK button
00554      */
00555     private void checkFields() 
00556     {
00557         // Prevent crash on Windows b/c of Eclipse's lazy initialization
00558         if (comboBoxes[FieldDatabasePath] == null)
00559             return;
00560 
00561         if (tabFolder.getSelectionIndex() == 0) {
00562             if (!comboBoxes[FieldDatabasePath].getText().equals("")) { 
00563                 okButton.setEnabled(true);
00564             } else {
00565                 okButton.setEnabled(false);
00566             }
00567         } else {
00568             if (!(comboBoxes[0].getText().equals("")) && !(comboBoxes[1].getText().equals("")) && !(comboBoxes[2].getText().equals(""))) {
00569                 okButton.setEnabled(true);
00570             } else {
00571                 okButton.setEnabled(false);
00572             }
00573         }
00574     }
00575 
00576     /**********
00577      * test unit, called by JVM
00578      * 
00579      * @param args
00580      */
00581     public static void main(String []args) 
00582     {
00583         Display display = new Display ();
00584         Shell shell = new Shell(display);
00585         shell.setLayout(new FillLayout());
00586 
00587         shell.open();
00588         OpenDatabaseDialog dialog = new OpenDatabaseDialog(shell, null);
00589 
00590         if (dialog.open() == Dialog.OK) {
00591             System.out.println("ok");
00592             final String []arguments = dialog.args;
00593             for (String arg:arguments) 
00594             {
00595                 System.out.println("-> " + arg);
00596             }
00597         }
00598     }
00599 }

Generated on 5 May 2015 for HPCVIEWER by  doxygen 1.6.1