View Javadoc

1   package gov.nasa.pds.ltdt.gui;
2   
3   import gov.nasa.pds.ltdt.gui.configuration.LTDTKeys;
4   import gov.nasa.pds.ltdt.gui.util.DictionaryUtility;
5   import gov.nasa.pds.ltdt.gui.util.ProcessWaitGlassPane;
6   import gov.nasa.pds.ltdt.gui.util.Utility;
7   import gov.nasa.pds.tools.dict.Dictionary;
8   import gov.nasa.pds.tools.label.parser.ParseException;
9   
10  import java.awt.BorderLayout;
11  import java.awt.Color;
12  import java.awt.Container;
13  import java.awt.Dimension;
14  import java.awt.event.WindowAdapter;
15  import java.awt.event.WindowEvent;
16  import java.io.File;
17  import java.io.IOException;
18  import java.net.MalformedURLException;
19  import java.util.ArrayList;
20  import java.util.Enumeration;
21  import java.util.HashMap;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Properties;
26  import java.util.Set;
27  
28  import javax.swing.JFrame;
29  import javax.swing.JMenuBar;
30  import javax.swing.JOptionPane;
31  import javax.swing.JPanel;
32  import javax.swing.JSplitPane;
33  import javax.swing.JTextField;
34  import javax.swing.JToolBar;
35  
36  
37  
38  public class MainWindow extends JFrame { 
39  		 
40  	Container contp;
41  	private MainWindowListener wListener;
42  	
43  	public TemplateEditorPane editorPane=null;
44  	public DictionaryListPane dictListPane=null;
45  	public DictionaryDefinitionPane dictDefPane=null;
46  	public StatusPane statusPane = null;
47  	
48  	private JPanel leftPanel, rightPanel=null;
49  	 	
50  	private JSplitPane mainSplitPane, leftSplitPane, rightSplitPane = null;
51  	public JMenuBar bar=null;
52  	public JToolBar jtb=null;
53  	public Menu menu=null;
54  	public ProjectCreateDialog jdlgCreateNewProject = null;
55  	public ProjectCreateDialog jdlgSaveProjectAs = null;
56  	
57  	public JTextField jtfTest = null;
58  	
59  	// *** structure related to dictionary display and manipulation ***
60  
61  	// the dictionaryMap contains actual id to assist locate rest of the information at dictionaryMap
62  	// the Shorten format holds identifiers only for displaying purpose
63  	
64  	// Note: the long and short lists should be in sync, i.e. matching indexes
65  	// because the id at the long list is the key to find the complete definition inside
66  	// dictionaryMap
67  
68  	// complete mapping of keywords related to a project
69  	public KeywordMap dictionaryMap = new KeywordMap();
70  	
71  	// list of full treeEntryIDs, id only,  in long format (with --) 
72  	// or short (without --) format
73  	public String[] keywordFullLong = null;
74  	public String[] keywordFullShort = null;
75  	
76  	// list of treeEntryIDs as result of search in all types
77  	public String[] keywordSubLong = null;
78  	public String[] keywordSubShort = null;
79  	
80  	// list of treeEntryIDs to be displayed based on the filter (object or element)
81  	public String[] keywordDisplayLong = null; // the full version
82  	public String[] keywordDisplayShort=null;      // the shortened version without dictionary url
83  	
84  	// tracking of the latest display type, default is Element type
85  	public int requestedType = LTDTKeys.ELEMENT_TYPE;
86  	
87  	// tracking of the latest selected keyword. This keyword should still be highlighted
88  	// after search query is cleared. 
89  	// Note: this is the long id of the keyword to allow correctly
90  	// identify it in case there are multiple resources of this keyword name in a project 
91  	public String lastSelectedKeyword = "";
92  
93  	// a structure to hold WDD
94  	public Dictionary WDD = new Dictionary();
95  	
96  	// merged of all dictionaries, including the ones already defined in a project,
97  	// the newly imported ones, and WDD
98  	// This variable is cleared before opening a new project, and it's altered in realtime
99  	// whenever new keyword is created or a keyword defintion is altered. 
100 	public Dictionary mDictionary = new Dictionary();
101 	
102 	// if all components in the frame has been created
103 	// and the u/i is visible
104 	// This flag is needed since some listener got triggered before
105 	// the ui is displayed, which caused stack dump
106 	public boolean windowVisible = false;
107 	
108 	private HashMap commandLineParams;
109 	private String dictCmdline="";
110 	private Properties props;
111 	
112 	public MainWindow (HashMap commandLineParams, Properties props) {
113 
114 	//public MainWindow (HashMap config, ArrayList dList)  {
115 		//this.config = config;
116 		this.commandLineParams = commandLineParams;
117 		
118 		this.props = props;
119 		//this.dictionariesFromCommandArray =  DictionaryUtility.getDictionaryNameList(props.getProperty(LTDTKeys.DICTIONARIESFROMCOMMAND));
120 				
121 		setTitle ("LTDTool");
122 
123 		// initialization
124 
125 		getContentPane().setLayout(new BorderLayout());
126 		setDefaultLookAndFeelDecorated(true);
127 		// use JFrame.DO_NOTHING_ON_CLOSE here
128 		// because there'll be extra handling when user quit the tool
129 		this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
130 		
131 		contp = this.getContentPane();
132 		contp.setLayout(new BorderLayout());
133 			
134 		wListener = new MainWindowListener(props, commandLineParams, this);
135 		addWindowListener( wListener);
136 	
137 		// left panel contains the editor pane for templates
138 		// and a status pane. The status pane is not displayed during 
139 		// editing.
140 		leftPanel = Utility.createVerticalBoxPanel();
141 		
142 		editorPane = new TemplateEditorPane(props, this); 
143 		statusPane = new StatusPane();
144 		statusPane.stPanel.setVisible(true); 
145 		
146 		leftSplitPane = new JSplitPane
147 		(JSplitPane.VERTICAL_SPLIT, editorPane, statusPane.stPanel);
148 		
149 		leftSplitPane.setOneTouchExpandable(true);
150 		leftSplitPane.setResizeWeight(0.9);
151 		
152 		leftPanel.add(leftSplitPane);
153 
154 		// right panel contains two sub panels: top and bottom panel. 
155 		// top panel displays the label objects/elements and a search box
156 		// definition for any object/element selected on the top panel
157 		// is displayed on the bottom panel.
158 		rightPanel = Utility.createVerticalBoxPanel(); 		
159 		
160 		dictListPane = new DictionaryListPane(this);
161 			
162 		dictDefPane = new DictionaryDefinitionPane(this);
163 
164 		// put the list and definition panels into a split pane
165 		rightSplitPane = new JSplitPane
166 			(JSplitPane.VERTICAL_SPLIT, dictListPane, dictDefPane);
167 		
168 		rightSplitPane.setOneTouchExpandable(true);
169 		rightSplitPane.setResizeWeight(0.7);
170 		rightPanel.add(rightSplitPane);
171 	
172 		// the main split pane consists of the editing area (left panel) and
173 		// dictionary display area (right panel)
174 		mainSplitPane = new JSplitPane
175 			(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel);
176 		mainSplitPane.setOneTouchExpandable(true);
177 	
178 		// put components together
179 		
180 		contp.add(mainSplitPane);
181 
182 		// add menu bar and tool bar		
183 		menu = new Menu(props, this);
184 		bar = menu.getMenuBar();
185 		jtb = menu.getToolBar();
186 		
187 		
188 		setJMenuBar(bar); // menu bar
189 		contp.add(jtb, BorderLayout.NORTH); // tool bar
190 		
191 		setContentPane(contp);
192 
193 		pack();
194 		setVisible(true);
195 		this.windowVisible = true;
196 	}
197 
198 	
199 	private class MainWindowListener extends WindowAdapter {
200 		
201 		private Properties props;
202 		private MainWindow window;
203 		private HashMap commandLineParams;
204 		private String[] dictionariesFromCommandArray;
205 		
206 		
207 		//private ArrayList dictList;
208 		
209 
210 		private int toolOpenStatus = 0;
211 		
212 		
213 		public MainWindowListener (Properties props, HashMap commandLineParams, MainWindow window){
214 			
215 			this.commandLineParams = commandLineParams;
216 			this.window = window;
217 			this.props = props;
218 			
219 			dictionariesFromCommandArray = 
220 				DictionaryUtility.getDictionaryNameArray(props.getProperty(LTDTKeys.DICTIONARIESFROMCOMMAND));
221 		}
222 		/**
223 		 * windowClosing event handling
224 		 */		
225 		public void windowClosing (WindowEvent we) {
226 			ToolExit.exitHandling(props, window);
227 		} // windowClosing event
228 
229 		/***
230 		 * windowOpen event handling
231 		 */
232 		public void windowOpened (WindowEvent we) {
233 
234 			initializeSessionConfig();
235 
236 			if ("true".equals(props.getProperty("debug"))) {	
237 				System.err.println ("..........................................");
238 				System.err.println ("LTDT Session has been initialized with ...");
239 				for (Enumeration e= props.propertyNames(); e.hasMoreElements();) {
240 					String key = e.nextElement().toString();
241 					System.err.println (key+"="+props.getProperty(key));
242 				}
243 				
244 				System.err.println("open status is "+toolOpenStatus);
245 				System.err.println (".........................................");
246 						
247 			};
248 					
249 		} // windowOpened event
250 		
251 		/***
252 		 * This is only called once when the tool is starting up.
253 		 * It gathering initial set of properties bases on user input and 
254 		 * previous configuration data.
255 		 * The initial property values may be altered as the session progress
256 		 * 
257 		 * Alternatively, project directory and data dictionaries can be entered through command line.  
258 		 * @throws IOException 
259 		 *
260 		 */
261 		private void initializeSessionConfig ()  {
262 
263 			//
264 			// Design idea: 
265 			// 
266 			// If no project registered, remind the user to create new projects and open an untitled project
267 			//
268 			// Regardless whether project path is specified or not, load in command line 
269 			// dictionary specification at tool start up time
270 			// 
271 			// If project path is specified on command line --
272 			// - if the project path given by the user is not found, or
273 			//   if no project path provided
274 			//     inform user to choose between create a new project 
275 			//     or choose a project to open
276 			//       The list of projects is based on the .ltdt file at users
277 			//       home directory. If the file is empty or does not contain valid objects
278 			//       then consider there's no valid projects
279 			// - if the project path given by the user is found but no 
280 			//     project property information found, inform user to 
281 			//     choose between create a new project open an existing project
282 			// - if project path is found and new dictionaries were given on the command line
283 			//     add the new dictionaries into this project
284 			//  - For now, any property setting that's not in K=V format 
285 			//     inside the property.lst file is ignored
286 			//  
287 			//	PROJECTALTERED flag will be set to true when a project is created  
288 	        //         or when template got altered after a project is open
289 			//         or when new dictionary was imported 
290 	        //         or when wdd was created or altered after a project is open
291 			//         or when a command line specified dictionary got loaded to an untitled project
292 			//         ( or when a command line specified dictionary is not in the list of dictionaries for a project)
293 
294 
295 			
296 			String path = null;
297 			Set mappings = commandLineParams.entrySet();
298 			File fn = null;
299 			
300 			/////////////////////			
301 			if ("true".equals(props.getProperty("debug"))) {	
302 					System.err.println ("/////////////////////");
303 					System.err.println ("\nParameters from command line:");				
304 					if (mappings.size() > 0) {
305 						for (Iterator it=mappings.iterator(); it.hasNext(); ) {
306 							Map.Entry me = (Map.Entry)it.next();
307 							System.err.println (me);	//me.getKey(), me.getValue())
308 						}
309 					}
310 					else 
311 						System.err.println ("No parameters entered from command line.");
312 						
313 					System.err.println ("Dictionary entered at command line was:");
314 			
315 					if (dictionariesFromCommandArray != null)
316 						for (int i=0; i<dictionariesFromCommandArray.length; i++) {
317 							System.err.println(dictionariesFromCommandArray[i]);
318 						
319 						}
320 				System.err.println (">>>>>>>>>>>>");
321 			}
322 			////////////////////	
323 
324 			//	If the LTDT tool profile (i.e. .ltdt file) is not found, create one at users home directory
325 			//  Exit the tool if there is a problem.
326 			
327 			try {
328 				File toolPropertyFile = new File (LTDTKeys.LTDTPROPFILE);
329 				
330 				if (!toolPropertyFile.exists()) {
331 					new File(LTDTKeys.LTDTPROPFILE).createNewFile();
332 					toolOpenStatus = LTDTKeys.NO_PROJECT_REGISTERED;
333 				}
334 			}
335 			catch (IOException ie) {
336 				JOptionPane.showMessageDialog(
337 						window, 
338 						"Problem starting LTDTool. Cannot initialize tool profile information.");
339 				System.exit(-1);
340 			}
341 			
342 			
343 			// read in command line parameters into the property object
344 			// Note: dictionaries specified at the command line (-d)
345 			// has been stored at "props" under props.commandline.dictionaries
346 			// i.e. LTDTKeys.DICTIONARIESFROMCOMMAND
347 			dictCmdline = (String)props.getProperty(LTDTKeys.DICTIONARIESFROMCOMMAND).trim();
348 			
349 			if (dictCmdline.length()>0) {
350 				props.setProperty(LTDTKeys.COMMANDLINEDICTIONARYADDED,"true");
351 			}
352 			else {
353 				props.setProperty(LTDTKeys.COMMANDLINEDICTIONARYADDED,"false");
354 
355 			}
356 			
357 			try {
358 				if (commandLineParams.get(LTDTKeys.PROJECTDIR) == null) {
359 				
360 					path = null;
361 					
362 					if (Utility.getKeyList(LTDTKeys.LTDTPROPFILE).size()>0)
363 						toolOpenStatus = LTDTKeys.NO_PROJECTDIR_INFO;	
364 					else toolOpenStatus = LTDTKeys.NO_PROJECT_REGISTERED;
365 					 
366 					props.setProperty(LTDTKeys.PROJECTNAME, LTDTKeys.UNTITLED);
367 					
368 
369 				}
370 				else {
371 					String commandLineProjectDir = (String)commandLineParams.get(LTDTKeys.PROJECTDIR);
372 
373 					fn = new File(commandLineProjectDir);
374 
375 					// some validation
376 					
377 					if (fn.exists()==false) {
378 						// if project directory was given on command line, but not found
379 						// the directory path given by the user is temporarily kept  
380 						// for reporting purpose
381 						path = commandLineProjectDir;
382 						toolOpenStatus = LTDTKeys.PROJECTDIR_NOT_FOUND;					
383 					}
384 					else {  // if the user specified project directory is correct
385 						
386 						// get the fully-qualified / absolute path for project location
387 						// in case user specified related path for project on the command line
388 						path = fn.getCanonicalPath();
389 					
390 						props.setProperty(LTDTKeys.PROJECTDIR, path	);
391 						
392 						// if no project property file in this directory
393 						if (new File(path+System.getProperty("file.separator")+LTDTKeys.PROPERTYFILENAME).exists() == false && 
394 								Utility.dirRWAllowed(path)==false) {
395 							toolOpenStatus = LTDTKeys.FOUND_PROJECTDIR_NO_PROPERTY_AND_NOT_READWRITEABLE;
396 							
397 						}
398 						else if (new File(path+System.getProperty("file.separator")+LTDTKeys.PROPERTYFILENAME).exists() == false) {
399 							toolOpenStatus = LTDTKeys.FOUND_PROJECTDIR_NO_PROPERTY;						
400 						}						
401 						// if this directory is not read or writable
402 						else if (Utility.dirRWAllowed(path)==false) {							
403 							toolOpenStatus = LTDTKeys.PROJECTDIR_NOT_READWRITEABLE;							
404 						}
405 						// all requirements met
406 						else {
407 							toolOpenStatus = LTDTKeys.PROJECTDIR_PROPERTY_FOUND;	
408 							props.setProperty(LTDTKeys.PROJECTNAME, Utility.getProjectName(props.getProperty(LTDTKeys.PROJECTDIR)));
409 						}
410 					}				
411 				} // end reading and checking command line information
412 			
413 			}
414 			catch (IOException ex) {
415 				// do nothing
416 			}
417 
418 		
419 					
420 			try {
421 				
422 				if (toolOpenStatus == LTDTKeys.PROJECTDIR_PROPERTY_FOUND ) {				
423 						
424 					int openStatus = ProjectOpen.open(props, window, props.getProperty(LTDTKeys.PROJECTNAME), true);
425 
426 
427 					if (openStatus==LTDTKeys.FOUND_PROJECTDIR_NO_PROPERTY) {
428 						initializeNewWorkspace(window, openStatus);
429 						if ("false".equals(props.getProperty(LTDTKeys.PROJECTALTERED)))
430 							new ProjectGalleryDialog (props, window, LTDTKeys.PROJECTGALLERYTITLE, LTDTKeys.NEWFROMTEMPLATETABINDEX);
431 					}	
432 				}
433 									
434 				else {  // if anything other than PROJECTDIR_PROPERTY_FOUND
435 					warningCreateNewWorkspace (window, path);
436 					initializeNewWorkspace (window, toolOpenStatus);
437 					if ("false".equals(props.getProperty(LTDTKeys.PROJECTALTERED)))
438 						new ProjectGalleryDialog (props, window, LTDTKeys.PROJECTGALLERYTITLE, LTDTKeys.NEWFROMTEMPLATETABINDEX);
439 				}
440 				
441 				
442 			}
443 			catch (Exception ex) {
444 				
445 				JOptionPane.showMessageDialog(window, "Error initiating LTDT Tool\n");
446 				
447 			}
448 
449 		} // end of initSessionConfig
450 		
451 		/***
452 		 * Initialize a session with generic property value set 
453 		 * if user did not provide project info, or if project info is not valid.
454 		 */
455 		private void initializeNewWorkspace(final MainWindow window, int initialStatus) {
456 	
457 			Utility.initializeEmptyProject(props, window);
458 			
459 			window.setTitle("LTDTool (Project Name: "+LTDTKeys.UNTITLED+")");
460 			
461 			//window.dictListPane.jtp.setSelectedIndex(LTDTKeys.ALLTABINDEX);
462 
463 			props.setProperty(LTDTKeys.PROJECTNAME, LTDTKeys.UNTITLED);
464 						
465 			if (initialStatus == LTDTKeys.NO_PROJECTDIR_INFO || 
466 				initialStatus == LTDTKeys.NO_PROJECT_REGISTERED ||
467 				initialStatus == LTDTKeys.PROJECTDIR_NOT_READWRITEABLE ) {
468 				props.setProperty(LTDTKeys.PROJECTDIR, System.getProperty("user.dir"));
469 			}
470 			else props.setProperty(LTDTKeys.PROJECTDIR, props.getProperty(LTDTKeys.PROJECTDIR));
471 						
472 			props.setProperty(LTDTKeys.TEMPLATETYPE, "");     //template type - not used at this point
473 			props.setProperty(LTDTKeys.TEMPLATEEXISTS, "false");
474 			props.setProperty(LTDTKeys.WDDEXISTS, "false");
475 			
476 			// Even if no project was specified, we still want to load in dictionaries
477 			// provided by user via -d on command line
478 			
479 
480 			if ("true".equals(props.getProperty("debug")))
481 				System.err.println ("Command line dictionary specification was: "+dictCmdline);
482 			
483 			if (dictCmdline.length() >0 ) {
484 
485 				// handle loading of command line specified dictionaries 
486 				// on a separate thread and display a wait message
487 				final ProcessWaitGlassPane pw4 = new ProcessWaitGlassPane();
488 				window.setGlassPane(pw4);
489 				pw4.setBackground( new Color(255, 255, 255, 255) ); // white glass pane
490 				pw4.setForeground( Color.LIGHT_GRAY); // message in dark gray
491 
492 				pw4.activate("Opening project. Please wait ...");	
493 				Thread thread = new Thread()
494 				{
495 					public void run()
496 					{
497 				
498 						try {			
499 							window.mDictionary = DictionaryUtility.MergeDictionaryList(window.mDictionary, Utility.rowstring2urllist(dictCmdline)  );			
500 						}
501 						catch ( MalformedURLException me) {
502 							JOptionPane.showMessageDialog(window, "Error when construction runtime merged dictionary. "+me.getMessage());
503 						}
504 						catch (ParseException pe) {
505 							JOptionPane.showMessageDialog(window,"Error when construction runtime merged dictionary. "+pe.getMessage());				
506 						}
507 						catch (IOException ie) {
508 							JOptionPane.showMessageDialog(window, "Error when construction runtime merged dictionary. "+ie.getMessage());
509 						}
510 
511 			 			ProjectOpen.populateKeywords(props, window, dictCmdline);
512 			 			DictionaryUtility.populateDictionaryFullListingPane(window);
513 						// populate LTDTKeys.DICTIONARIES
514 			 			props.setProperty(LTDTKeys.DICTIONARIES, dictCmdline);
515 						props.setProperty(LTDTKeys.COMMANDLINEDICTIONARYADDED, "true");
516 						props.setProperty(LTDTKeys.PROJECTALTERED, "true");
517 						
518 						DictionaryListPane.displaySingleTypeList(window, LTDTKeys.ELEMENTONLY);
519 		
520 						pw4.deactivate();
521 					}
522 				};
523 				thread.start();
524 			}
525 			// if no dictionary read in from command line, then
526 			else {
527 				props.setProperty(LTDTKeys.DICTIONARIES, "");
528 				props.setProperty(LTDTKeys.COMMANDLINEDICTIONARYADDED, "false");
529 				props.setProperty(LTDTKeys.PROJECTALTERED, "false");
530 
531 			}			
532 
533 		} // end of initNewWorkspace
534 		
535 		private void warningCreateNewWorkspace (MainWindow window, String path) {
536 			String message=null;
537 			boolean foundLTDTProfile = false;
538 			
539 			//check if any project registered with LTDT. If so, give more hint to user
540 			try {					
541 				if (Utility.getKeyList(LTDTKeys.LTDTPROPFILE).size() > 0 )
542 					foundLTDTProfile = true;
543 				
544 			}
545 			catch (IOException ex) {
546 				// do nothing
547 			}
548 
549 			// construct general message
550 			switch (toolOpenStatus) {
551 
552 	
553 				case LTDTKeys.NO_PROJECT_REGISTERED:
554 				case  LTDTKeys.NO_PROJECTDIR_INFO:
555 					break;
556 				
557 				case LTDTKeys.PROJECTDIR_NOT_FOUND: 
558 					message = "Welcome to LTDTool. \nProject directory "+path+" can not be located. \nPlease create a new project ";
559 					if (foundLTDTProfile==true)
560 						message = message + " \nor open an existing project";
561 					JOptionPane.showMessageDialog(window, message);
562 					break;
563 					
564 				case LTDTKeys.FOUND_PROJECTDIR_NO_PROPERTY_AND_NOT_READWRITEABLE:
565 					message = "Welcome to LTDTool. \nProject information was not found at "+path+" \n and the directory is not readable or writable." +
566 							"\nPlease create a new project ";
567 					if (foundLTDTProfile==true)
568 						message = message + " \nor open an existing project";
569 					JOptionPane.showMessageDialog(window, message);
570 					break;
571 				case LTDTKeys.FOUND_PROJECTDIR_NO_PROPERTY: 
572 					message = "Welcome to LTDTool. \nProject information was not found at "+path+" \nPlease create a new project ";
573 					if (foundLTDTProfile==true)
574 						message = message + " \nor open an existing project";
575 					JOptionPane.showMessageDialog(window, message);
576 					break;
577 				case LTDTKeys.PROJECTDIR_NOT_READWRITEABLE:
578 					message = "Welcome to LTDTool. \nProject directory "+path+" is not readable or writable. \nPlease correct the file permission setting ";
579 					if (foundLTDTProfile==true) {
580 						message = message + " \nor open an existing project";	
581 					
582 						JOptionPane.showMessageDialog(window, message);
583 					}
584 					else {
585 						JOptionPane.showMessageDialog(window, message);
586 					}
587 				default:;
588 				
589 			}
590 			
591 			
592 		} // end warningCreateNewWorkspace
593 		
594 	} // end MainWindowListener class
595 
596 		
597 	public JFrame getWindow() {
598 		return this;
599 	}
600 	
601 
602 	MainWindowListener getListener() {
603 		return wListener;
604 	}
605 }