View Javadoc

1   /*
2    *  
3    *  Fosstrak LLRP Commander (www.fosstrak.org)
4    * 
5    *  Copyright (C) 2008 ETH Zurich
6    *
7    *  This program is free software: you can redistribute it and/or modify
8    *  it under the terms of the GNU General Public License as published by
9    *  the Free Software Foundation, either version 3 of the License, or
10   *  (at your option) any later version.
11   *
12   *  This program is distributed in the hope that it will be useful,
13   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   *  GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License
18   *  along with this program.  If not, see <http://www.gnu.org/licenses/> 
19   *
20   */
21  
22  package org.fosstrak.llrp.commander.editors;
23  
24  import org.apache.log4j.Logger;
25  import org.eclipse.core.runtime.IProgressMonitor;
26  import org.eclipse.jface.action.Action;
27  import org.eclipse.jface.action.IMenuListener;
28  import org.eclipse.jface.action.IMenuManager;
29  import org.eclipse.jface.action.MenuManager;
30  import org.eclipse.jface.dialogs.MessageDialog;
31  import org.eclipse.jface.preference.IPreferenceStore;
32  import org.eclipse.jface.viewers.TreeViewer;
33  import org.eclipse.swt.SWT;
34  import org.eclipse.swt.widgets.Menu;
35  import org.eclipse.swt.widgets.Tree;
36  import org.eclipse.swt.widgets.TreeColumn;
37  import org.eclipse.ui.IEditorInput;
38  import org.eclipse.ui.PartInitException;
39  import org.eclipse.ui.PlatformUI;
40  import org.eclipse.ui.forms.editor.FormEditor;
41  import org.fosstrak.llrp.commander.LLRPPlugin;
42  import org.fosstrak.llrp.commander.ResourceCenter;
43  import org.fosstrak.llrp.commander.dialogs.SendMessageDialog;
44  import org.fosstrak.llrp.commander.editors.graphical.GraphicalEditorPage;
45  import org.fosstrak.llrp.commander.preferences.PreferenceConstants;
46  import org.llrp.ltk.exceptions.InvalidLLRPMessageException;
47  import org.llrp.ltk.types.LLRPMessage;
48  
49  /**
50   * This editor extended Eclipse FormEditor, which contains multiple pages.
51   * 
52   * It provides one XML Editor page, one Graphics Editor page, and one Binary
53   * format viewer.
54   * 
55   * In this multiple page editor, those three page works on the same message
56   * file, but only XML editor touch the file system. Once the message changed,
57   * XML Editor pass the LLRPBitList to Binary Viewer to update the binary format.
58   * 
59   * The target file will be stored under one Eclipse project.
60   * 
61   * @author Haoning Zhang
62   * @version 1.0
63   */
64  public class LLRPEditor extends FormEditor {
65  
66  	/**
67  	 * Log4j instance.
68  	 */
69  	private static Logger log = Logger.getLogger(LLRPEditor.class);
70  
71  	/**
72  	 * Page Caption of XML Editor.
73  	 */
74  	private final static String SOURCE_PAGE_TITLE = "XML Editor";
75  
76  	/**
77  	 * Page Caption of Binary Viewer.
78  	 */
79  	private final static String BINARY_PAGE_TITLE = "Binary Viewer";
80  
81  	private TreeViewer treeViewer;
82  	private TreeColumn keyColumn, valueColumn;
83  	private XMLEditor textEditor;
84  	private LLRPBinaryContentProvider provider;
85  	
86  	private GraphicalEditorPage graphicsPage;
87  	
88  	private final static int PAGE_GRAPHICS 	= 0;
89  	private final static int PAGE_XML 		= 1;
90  	private final static int PAGE_BINARY 	= 2;
91  	
92  	private int oldPageIndex = PAGE_XML;
93  	
94  	private Action actionSend;
95  
96  	/**
97  	 * Extends <code>FormEditor.addPages()</code> Initial three pages involved
98  	 * in this FormEditor
99  	 */
100 	protected void addPages() {
101 
102 		createActions();
103 		
104 		// Page No.0
105 		try {
106 			log.debug("Creating Graphics Editor Page...");
107 			graphicsPage = new GraphicalEditorPage(this);
108 			addPage(graphicsPage);
109 		} catch (PartInitException e) {
110 			e.printStackTrace();
111 		}
112 		
113 		// Page No.1
114 		log.debug("Creating XML Editor Page...");
115 		createSourcePage();
116 		
117 		// Page No.2
118 		log.debug("Creating Binary Viewer Page...");
119 		createBinaryPage();
120 		
121 		// initialize graphical editor and binary viewer with content from xml editor
122 		boolean graphicalEditorSuccessfullyInitialized = updateGraphicalEditor();
123 		boolean binaryViewerSuccessfullyInitialized = updateBinaryViewer();
124 		
125 		IPreferenceStore store = LLRPPlugin.getDefault().getPreferenceStore();
126 		String defaultEditor = store.getString(PreferenceConstants.P_DEFAULT_EDITOR);
127 		
128 		if (defaultEditor.equals(PreferenceConstants.P_DEFAULT_EDITOR_GRAPHICAL)
129 				&& graphicalEditorSuccessfullyInitialized){
130 			setActivePage(PAGE_GRAPHICS);
131 		}
132 		else if (defaultEditor.equals(PreferenceConstants.P_DEFAULT_EDITOR_BINARY)
133 				&& binaryViewerSuccessfullyInitialized){
134 			setActivePage(PAGE_BINARY);
135 		}
136 		else{
137 			setActivePage(PAGE_XML);
138 		}
139 		
140 		updateTitle();
141 	}
142 
143 	/**
144 	 * Create related Eclipse action classes.
145 	 */
146 	private void createActions() {
147 		actionSend = new Action() {
148 			public void run() {
149 				SendMessageDialog.getInstance(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()).open();
150 			}
151 		};
152 		actionSend.setText("Send LLRP Message");
153 		actionSend.setToolTipText("Send LLRP Message");
154 		actionSend.setImageDescriptor(ResourceCenter.getInstance().getImageDescriptor("Send_LLRP.gif"));
155 	}
156 
157 	/**
158 	 * Create the Binary Message Viewer
159 	 */
160 	private void createBinaryPage() {
161 		treeViewer = new TreeViewer(getContainer(), SWT.MULTI
162 				| SWT.FULL_SELECTION);
163 		Tree tree = treeViewer.getTree();
164 		tree.setHeaderVisible(true);
165 
166 		keyColumn = new TreeColumn(tree, SWT.LEFT);
167 		keyColumn.setText("Key");
168 		keyColumn.setWidth(150);
169 		valueColumn = new TreeColumn(tree, SWT.LEFT);
170 		valueColumn.setText("Value");
171 		valueColumn.setWidth(420);
172 		valueColumn.setResizable(false);
173 
174 		int index = addPage(treeViewer.getControl());
175 		setPageText(index, BINARY_PAGE_TITLE);
176 		
177 		
178 		MenuManager menuMgr = new MenuManager("#PopupMenu");
179 		menuMgr.setRemoveAllWhenShown(true);
180 		menuMgr.addMenuListener(new IMenuListener() {
181 			public void menuAboutToShow(IMenuManager manager) {
182 				manager.add(actionSend);
183 			}
184 		});
185 		Menu menu = menuMgr.createContextMenu(treeViewer.getControl());
186 		treeViewer.getControl().setMenu(menu);
187 		getSite().registerContextMenu(menuMgr, treeViewer);
188 		
189 
190 		initTreeContent();
191 	}
192 
193 	/**
194 	 * Initialize the tree structure in Binary Viewer.
195 	 */
196 	private void initTreeContent() {
197 		provider = new LLRPBinaryContentProvider();
198 		treeViewer.setContentProvider(provider);
199 		treeViewer.setLabelProvider(new LLRPBinaryLabelProvider());
200 
201 		treeViewer.setInput(new BinaryMessage());
202 		treeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);
203 	}
204 
205 	/**
206 	 * Create XML Message Editor
207 	 */
208 	private void createSourcePage() {
209 		try {
210 
211 			textEditor = new XMLEditor();
212 
213 			int index = addPage(textEditor, getEditorInput());
214 			setPageText(index, SOURCE_PAGE_TITLE);
215 
216 		} catch (PartInitException e) {
217 			e.printStackTrace();
218 		}
219 	}
220 
221 	/**
222 	 * When user change the page, the content should be synchronized here.
223 	 */
224 	protected void pageChange(int aNewPageIndex) {
225 		
226 		if (oldPageIndex == aNewPageIndex){
227 			return;
228 		}
229 		
230 		// commit any changes of the old page to the xml editor
231 		if (oldPageIndex == PAGE_GRAPHICS){
232 			if (graphicsPage.isGraphicalEditorDirty()){
233 				boolean success = commitGraphicalEditor();
234 				if (!success){
235 					setActivePage(PAGE_GRAPHICS);
236 					showSwitchErrorMessage();
237 					return;
238 				}
239 			}
240 		}
241 		
242 		// update the new page with the content from the xml editor
243 		if (aNewPageIndex == PAGE_GRAPHICS){
244 			boolean success = updateGraphicalEditor();
245 			if (!success){
246 				setActivePage(oldPageIndex);
247 				showSwitchErrorMessage();
248 				return;
249 			}
250 		}
251 		else if (aNewPageIndex == PAGE_BINARY){
252 			boolean success = updateBinaryViewer();
253 			if (!success){
254 				setActivePage(oldPageIndex);
255 				showSwitchErrorMessage();
256 				return;
257 			}
258 		}
259 		oldPageIndex = aNewPageIndex;
260 		
261 		super.pageChange(aNewPageIndex);
262 	}
263 
264 	private void updateTitle() {
265 		IEditorInput input = getEditorInput();
266 		// use setPartName instead of old setTitle
267 		setPartName(input.getName());
268 		
269 		// we could use setContentDescription(String) to set a nice 
270 		// description on top of the pane...
271 		
272 		setTitleToolTip(input.getToolTipText());
273 	}
274 
275 	public void setFocus() {
276 		switch (getActivePage()) {
277 		case 1:
278 			treeViewer.getTree().setFocus();
279 			break;
280 		case 0:
281 			textEditor.setFocus();
282 			break;
283 		}
284 	}
285 
286 	/**
287 	 * Here the XML Editor Page save the content.
288 	 */
289 	public void doSave(IProgressMonitor aMonitor) {
290 		if ((getActivePage() == PAGE_GRAPHICS) && (!commitGraphicalEditor())){
291 			showSaveErrorMessage();
292 			return;
293 		}
294 		textEditor.doSave(aMonitor);
295 	}
296 
297 	/**
298 	 * Always true.
299 	 */
300 	public boolean isSaveAsAllowed() {
301 		return true;
302 	}
303 
304 	/**
305 	 * Here the XML Editor Page save as the content.
306 	 */
307 	public void doSaveAs() {
308 		if ((getActivePage() == PAGE_GRAPHICS) && (!commitGraphicalEditor())){
309 			showSaveErrorMessage();
310 			return;
311 		}
312 		textEditor.doSaveAs();
313 		setInput(textEditor.getEditorInput());
314 		updateTitle();
315 	}
316 	
317 	/**
318 	 * Marks the XML Editor as dirty.
319 	 */
320 	public void markXMLEditorAsDirty(){
321 		String xmlContent = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()).get();
322 		textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()).set(xmlContent);
323 	}
324 	
325 	/**
326 	 * Commits any changes made in the graphical editor to the xml editor.
327 	 * 
328 	 * @return <code>true</code> if the commit operation was successful, and <code>false</code> otherwise
329 	 * (e.g. if the message object could not be serialized to xml)
330 	 */
331 	private boolean commitGraphicalEditor() {
332 		LLRPMessage message = graphicsPage.getLLRPMessage();
333 		if (message == null) {
334 			return false;
335 		}
336 		
337 		String xmlContent = "";
338 		boolean success;
339 		try {
340 			xmlContent = message.toXMLString();
341 			textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()).set(xmlContent);
342 			graphicsPage.setDirty(false);
343 			success = true;
344 		} catch (InvalidLLRPMessageException e) {
345 			success = false;
346 		}
347 		return success;
348 	}
349 	
350 	/**
351 	 * Updates the graphical editor with the content of the xml editor.
352 	 * 
353 	 * @return  <code>true</code> if the update operation was successful, and <code>false</code> otherwise
354 	 * (e.g. if the xml string could not be deserialized to a message object).
355 	 */
356 	private boolean updateGraphicalEditor(){
357 		String xmlContent = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()).get();
358 		LLRPMessage message = ResourceCenter.getInstance().generateLLRPMessage(xmlContent);
359 		
360 		boolean success;
361 		if (message == null){
362 			success = false;
363 		}
364 		else{
365 			graphicsPage.setLLRPMessage(message);
366 			success = true;
367 		}
368 		return success;
369 	}
370 	
371 	/**
372 	 * Updates the binary viewer with the content of the xml editor.
373 	 * 
374 	 * @return  <code>true</code> if the update operation was successful, and <code>false</code> otherwise
375 	 * (e.g. if the xml string could not be deserialized to a message object).
376 	 */
377 	private boolean updateBinaryViewer(){
378 		String xmlContent = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()).get();
379 		LLRPMessage message = ResourceCenter.getInstance().generateLLRPMessage(xmlContent);
380 		
381 		boolean success;
382 		if (message == null){
383 			success = false;
384 		}
385 		else{
386 			String content = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()).get();
387 			BinaryMessage msg;
388 			try {
389 				msg = new BinaryMessage(content);
390 			} catch (Exception e) {
391 				return false;
392 			}
393 			treeViewer.setInput(msg);
394 			success = true;
395 		}
396 		return success;
397 	}
398 	
399 	/**
400 	 * Shows an error message saying that the message cannot be saved.
401 	 */
402 	private void showSaveErrorMessage(){
403 		String title = "Cannot save the message";
404 		String message = "The message cannot be saved because it is not valid.";
405 		MessageDialog.openError(this.getContainer().getShell(), title, message);
406 	}
407 	
408 	/**
409 	 * Shows an error message saying that the page cannot be switched.
410 	 */
411 	private void showSwitchErrorMessage(){
412 		String title = "Cannot switch the page";
413 		String message = "The page cannot be switched because the message is not valid.";
414 		MessageDialog.openError(this.getContainer().getShell(), title, message);
415 	}
416 
417 }