001: package net.sourceforge.tracelog.ui;
002:
003: import java.util.HashSet;
004: import java.util.LinkedList;
005: import java.util.List;
006:
007: import net.sourceforge.tracelog.config.ConfigFile;
008: import net.sourceforge.tracelog.config.ConfigFileFactory;
009: import net.sourceforge.tracelog.config.LogFile;
010: import net.sourceforge.tracelog.listeners.FileListener;
011: import net.sourceforge.tracelog.listeners.LogSizeHandler;
012: import net.sourceforge.tracelog.listeners.LogViewerHandler;
013: import net.sourceforge.tracelog.utils.Util;
014:
015: import org.apache.log4j.Logger;
016: import org.eclipse.swt.SWT;
017: import org.eclipse.swt.custom.StyledText;
018: import org.eclipse.swt.events.SelectionAdapter;
019: import org.eclipse.swt.events.SelectionEvent;
020: import org.eclipse.swt.graphics.Font;
021: import org.eclipse.swt.graphics.Image;
022: import org.eclipse.swt.layout.GridData;
023: import org.eclipse.swt.layout.GridLayout;
024: import org.eclipse.swt.widgets.Composite;
025: import org.eclipse.swt.widgets.Control;
026: import org.eclipse.swt.widgets.MessageBox;
027: import org.eclipse.swt.widgets.TabFolder;
028: import org.eclipse.swt.widgets.TabItem;
029: import org.eclipse.swt.widgets.ToolBar;
030: import org.eclipse.swt.widgets.ToolItem;
031:
032: public class ShellMainLogGroupTabFolder extends AbstractWidget {
033: public static final String LOG_VIEWER_DATA_KEY_SCROLL_LOCK = "scroll_lock";
034: private static Logger log = Logger
035: .getLogger(ShellMainLogGroupTabFolder.class);
036: private GridLayout buttonGridLayout;
037: private ConfigFile configFile;
038: private ConfigFileFactory configFileFactory;
039: private HashSet<Thread> daemonThreads;
040: private Image imageClearAll;
041: private Image imageStart;
042: private Image imageStop;
043: private List<LogFile> logFiles;
044: private StyledText mainLogST;
045: private TabFolder tabFolder;
046:
047: ShellMainLogGroupTabFolder(IMediator mediator,
048: List<LogFile> logFiles, TabFolder tabFolder) {
049: super ();
050: super .mediator = mediator;
051: this .logFiles = logFiles;
052: this .tabFolder = tabFolder;
053: this .daemonThreads = new HashSet<Thread>();
054: this .mainLogST = null;
055: this .configFileFactory = ConfigFileFactory.getInstance();
056: this .configFile = configFileFactory.getConfigFile();
057:
058: this .imageStop = new Image(display, Util
059: .getOwnResource(projectProperties.getIconStop()));
060: this .imageStart = new Image(display, Util
061: .getOwnResource(projectProperties.getIconStart()));
062: this .imageClearAll = new Image(display, Util
063: .getOwnResource(projectProperties.getIconClearAll()));
064:
065: buttonGridLayout = new GridLayout(5, false);
066: buttonGridLayout.marginHeight = 0;
067: buttonGridLayout.marginWidth = 0;
068: buttonGridLayout.horizontalSpacing = 2;
069: buttonGridLayout.verticalSpacing = 0;
070: }
071:
072: public void clearAllLogViewers() {
073: for (TabItem tabItem : tabFolder.getItems()) {
074: StyledText styledText = getLogViewer((Composite) tabItem
075: .getControl());
076: styledText.setText("");
077: }
078: }
079:
080: public void destroy() {
081: destroyAllLogDaemons();
082: removeTabItems();
083: }
084:
085: /**
086: * Determines and returns the log viewer from the composite.
087: *
088: * @param composite
089: * Composite that contains the log viewer.
090: * @return Log viewer.
091: */
092: public StyledText getLogViewer(Composite composite) {
093: for (Control control : composite.getChildren()) {
094: if (control instanceof StyledText) {
095: return (StyledText) control;
096: }
097: }
098: return null;
099: }
100:
101: public boolean isMainLogStarted() {
102: return getMainStartStopLogToolItem().getImage().equals(
103: imageStop);
104: }
105:
106: /**
107: * Sets up the tab items in the tab folder and then starts all log daemons.
108: */
109: public void run() {
110: destroy();
111: setupTabItems();
112: createAllLogDaemons();
113: }
114:
115: public void toogleStartStopMainLog(boolean toStopAllLogs) {
116: if (toStopAllLogs) {
117: stopAllLogs();
118: } else {
119: startAllLogs();
120: }
121: // handleStartStopLogEvent(getMainStartStopLogToolItem(), true);
122: }
123:
124: public void updateLogFont(Font font) {
125: for (TabItem tabItem : tabFolder.getItems()) {
126: StyledText styledText = getLogViewer((Composite) tabItem
127: .getControl());
128: styledText.setFont(font);
129: }
130: }
131:
132: /**
133: * Updates the log size handler for all log viewers based on the new purge
134: * strategy set by users.
135: *
136: * @param purgePercentage
137: * Total percentage to purge the log.
138: * @param logLineThreshold
139: * Max log line before purging kicks in.
140: */
141: public void updateLogSizeHandler(int purgePercentage,
142: int logLineThreshold) {
143: for (int i = 0; i < tabFolder.getItemCount(); ++i) {
144: TabItem tabItem = tabFolder.getItem(i);
145:
146: Composite composite = (Composite) tabItem.getControl();
147: StyledText logST = getLogViewer(composite);
148:
149: LogSizeHandler logSizeHandler = new LogSizeHandler(logST,
150: purgePercentage, logLineThreshold);
151:
152: // run it first to purge the log size if the existing log viewer
153: // already exceeds the new threshold
154: logSizeHandler.run();
155:
156: // store it the log viewer object
157: logST.setData(logSizeHandler);
158: }
159: }
160:
161: /**
162: * Clears the content in the active log viewer.
163: */
164: private void clearActiveLogViewer() {
165: getActiveLogViewer().setText("");
166: }
167:
168: /**
169: * Creates all log daemons and store them in a thread collection for easy
170: * reference.
171: */
172: private void createAllLogDaemons() {
173: // some daemon still exists, then kill them all first before recreating
174: // them. This may happen when user stops all logs, then starts
175: // single log first before attempting to start all logs. If the
176: // additional daemons are not removed, then there will be more than one
177: // daemon listening to the same log file in one log viewer, which in the
178: // sense doesn't accomplish anything useful.
179: if (!daemonThreads.isEmpty()) {
180: destroyAllLogDaemons();
181: }
182:
183: for (int i = 0; i < logFiles.size(); ++i) {
184: LogFile logFile = logFiles.get(i);
185: TabItem tabItem = tabFolder.getItem(i + 1);
186:
187: createLogDaemonThread(logFile, tabItem);
188: }
189: }
190:
191: /**
192: * Creates a log daemon thread and start it.
193: *
194: * @param logFile
195: * Log bean object.
196: * @param tabItem
197: * Tab item.
198: */
199: private void createLogDaemonThread(LogFile logFile, TabItem tabItem) {
200: Composite composite = (Composite) tabItem.getControl();
201: StyledText logST = getLogViewer(composite);
202: LogViewerHandler logViewerHandler = new LogViewerHandler(
203: logFile, mainLogST, logST);
204: FileListener listener = new FileListener(logViewerHandler,
205: logFile.getLogPath());
206:
207: Thread thread = new Thread(listener, logFile.getId());
208: thread.setDaemon(true);
209: thread.start();
210:
211: daemonThreads.add(thread);
212: }
213:
214: /**
215: * Creates log viewer composite that contains the viewer itself together
216: * with some action buttons.
217: *
218: * @param isMainLog
219: * Whether it is the main log or other logs.
220: * @return Newly created log viewer composite.
221: */
222: private Composite createLogViewerComposite(final boolean isMainLog) {
223: Composite composite = new Composite(tabFolder, SWT.NONE);
224: composite.setLayout(new GridLayout(2, false));
225:
226: StyledText st = null;
227:
228: // main log viewer
229: if (isMainLog) {
230: mainLogST = new StyledText(composite, SWT.BORDER
231: | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL
232: | SWT.READ_ONLY);
233: st = mainLogST;
234: }
235: // other log viewer
236: else {
237: st = new StyledText(composite, SWT.BORDER | SWT.MULTI
238: | SWT.H_SCROLL | SWT.V_SCROLL | SWT.READ_ONLY);
239: }
240:
241: st.setBackground(UIUtil.getColorWhite());
242: st.setLayoutData(new GridData(GridData.FILL_BOTH));
243:
244: // toolbar for organizing buttons
245: ToolBar toolbar = new ToolBar(composite, SWT.FLAT
246: | SWT.VERTICAL);
247: toolbar.setLayout(buttonGridLayout);
248: toolbar.setLayoutData(new GridData(
249: GridData.VERTICAL_ALIGN_BEGINNING));
250:
251: final ToolItem startStopTI = new ToolItem(toolbar, SWT.FLAT);
252: startStopTI.setImage(imageStop);
253: startStopTI.setToolTipText(isMainLog ? "Stop All Logs"
254: : "Stop Log");
255:
256: ToolItem clearTI = new ToolItem(toolbar, SWT.FLAT);
257: clearTI.setImage(new Image(display, Util
258: .getOwnResource(projectProperties.getIconClear())));
259: clearTI.setToolTipText("Clear Log");
260:
261: // is main log, then show clear all logs icon
262: if (isMainLog) {
263: ToolItem clearAllTI = new ToolItem(toolbar, SWT.FLAT);
264: clearAllTI.setImage(imageClearAll);
265: clearAllTI.setToolTipText("Clear All Logs");
266:
267: clearAllTI.addSelectionListener(new SelectionAdapter() {
268: public void widgetSelected(SelectionEvent e) {
269: clearAllLogViewers();
270: }
271: });
272: }
273: // not main log, then show open file icon
274: else {
275: ToolItem openFileTI = new ToolItem(toolbar, SWT.FLAT);
276: openFileTI.setImage(new Image(display,
277: Util.getOwnResource(projectProperties
278: .getIconOpenFile())));
279: openFileTI.setToolTipText("Open Log File");
280:
281: // open file button is clicked
282: openFileTI.addSelectionListener(new SelectionAdapter() {
283: public void widgetSelected(SelectionEvent e) {
284: handleOpenFile();
285: }
286: });
287: }
288:
289: final ToolItem scrollLockTI = new ToolItem(toolbar, SWT.CHECK);
290: scrollLockTI
291: .setImage(new Image(display, Util
292: .getOwnResource(projectProperties
293: .getIconScrollLock())));
294: scrollLockTI.setToolTipText("Scroll Lock");
295:
296: // start/stop listener
297: startStopTI.addSelectionListener(new SelectionAdapter() {
298: public void widgetSelected(SelectionEvent e) {
299: handleStartStopLogEvent(startStopTI, isMainLog);
300: }
301: });
302:
303: // clear button is clicked
304: clearTI.addSelectionListener(new SelectionAdapter() {
305: public void widgetSelected(SelectionEvent e) {
306: clearActiveLogViewer();
307: }
308: });
309:
310: // lock/unlock scroll
311: scrollLockTI.addSelectionListener(new SelectionAdapter() {
312: public void widgetSelected(SelectionEvent e) {
313: handleLogScroll(scrollLockTI);
314: }
315: });
316:
317: return composite;
318: }
319:
320: /**
321: * Creates the selected log viewer's daemon thread.
322: */
323: private void createSelectedLogDaemon() {
324: int selectedTabIndex = tabFolder.getSelectionIndex();
325: LogFile logFile = logFiles.get(selectedTabIndex - 1);
326: TabItem tabItem = tabFolder.getItem(selectedTabIndex);
327:
328: createLogDaemonThread(logFile, tabItem);
329: }
330:
331: /**
332: * Interrupts all log daemons and clear them from the thread collection.
333: */
334: private void destroyAllLogDaemons() {
335: for (Thread daemonThread : daemonThreads) {
336: daemonThread.interrupt();
337: }
338:
339: daemonThreads.clear();
340: }
341:
342: /**
343: * Interrupts the selected log viewer's daemon thread.
344: */
345: private void destroySelectedLogDaemon() {
346: LogFile logFile = getActiveLogFile();
347:
348: Thread daemonThread = getDaemonByName(logFile.getId());
349:
350: if (daemonThread != null) {
351: daemonThread.interrupt();
352:
353: daemonThreads.remove(daemonThread);
354: }
355: }
356:
357: private LogFile getActiveLogFile() {
358: // minus 1 is required because the first tab is main log
359: int selectedLogIndex = tabFolder.getSelectionIndex() - 1;
360: return logFiles.get(selectedLogIndex);
361: }
362:
363: /**
364: * Returns the active log viewer that is currently being viewed.
365: *
366: * @return Active log viewer.
367: */
368: private StyledText getActiveLogViewer() {
369: TabItem tabItem = tabFolder.getItem(tabFolder
370: .getSelectionIndex());
371: Composite composite = (Composite) tabItem.getControl();
372:
373: return getLogViewer(composite);
374: }
375:
376: private List<ToolItem> getAllStartStopLogToolItems() {
377: List<ToolItem> startStopTIs = new LinkedList<ToolItem>();
378:
379: for (TabItem tabItem : tabFolder.getItems()) {
380: Composite composite = (Composite) tabItem.getControl();
381: for (Control control : composite.getChildren()) {
382: if (control instanceof ToolBar) {
383: ToolBar toolbar = (ToolBar) control;
384:
385: for (ToolItem toolItem : toolbar.getItems()) {
386: if (hasStartStopImage(toolItem.getImage())) {
387: startStopTIs.add(toolItem);
388: }
389: }
390: }
391: }
392: }
393:
394: return startStopTIs;
395: }
396:
397: /**
398: * Returns the daemon thread by name.
399: *
400: * @param name
401: * Daemon thread name.
402: * @return Daemon thread if found, otherwise null.
403: */
404: private Thread getDaemonByName(String name) {
405:
406: for (Thread daemonThread : daemonThreads) {
407: if (daemonThread.getName().equals(name)) {
408: return daemonThread;
409: }
410: }
411:
412: return null;
413: }
414:
415: private ToolItem getMainStartStopLogToolItem() {
416: TabItem tabItem = tabFolder.getItem(0);
417: Composite composite = (Composite) tabItem.getControl();
418:
419: for (Control control : composite.getChildren()) {
420: if (control instanceof ToolBar) {
421: ToolBar toolBar = (ToolBar) control;
422:
423: for (ToolItem toolItem : toolBar.getItems()) {
424: if (hasStartStopImage(toolItem.getImage())) {
425: return toolItem;
426: }
427: }
428: }
429: }
430:
431: log
432: .error("Main start stop log tool item not found. Should not reach here.");
433: return null;
434: }
435:
436: /**
437: * Handles whether to lock or unlock the scrolling log viewer.
438: *
439: * @param scrollLockTI
440: * Scroll lock tool item.
441: */
442: private void handleLogScroll(ToolItem scrollLockTI) {
443: boolean toScrollLock = scrollLockTI.getSelection();
444:
445: if (toScrollLock) {
446: scrollLockTI.setToolTipText("Scroll Unlock");
447: } else {
448: scrollLockTI.setToolTipText("Scroll Lock");
449: }
450:
451: getActiveLogViewer().setData(LOG_VIEWER_DATA_KEY_SCROLL_LOCK,
452: toScrollLock);
453: }
454:
455: /**
456: * Determines the active tab to obtain which log to open, then opens the log
457: * file based on user's preferred default editor.
458: */
459: private void handleOpenFile() {
460: LogFile logFile = getActiveLogFile();
461:
462: String textEditorPath = configFile.getUserConfig()
463: .getTextEditorPath();
464:
465: try {
466: Runtime.getRuntime()
467: .exec(
468: new String[] { textEditorPath,
469: logFile.getLogPath() });
470: } catch (Exception ex) {
471: MessageBox mb = new MessageBox(parentShell, SWT.OK
472: | SWT.ICON_ERROR);
473: mb.setText("Error");
474: mb
475: .setMessage("Cannot launch this text editor: "
476: + textEditorPath
477: + "."
478: + Util.LINE_BREAK
479: + Util.LINE_BREAK
480: + "Please configure it under \"Edit\" --> \"Options...\" before trying it again.");
481: mb.open();
482: }
483: }
484:
485: /**
486: * Handles start and stop log events.
487: *
488: * @param startStopTI
489: * Tool item.
490: * @param isMainLog
491: * Whether it is a main log or not.
492: */
493: private void handleStartStopLogEvent(ToolItem startStopTI,
494: boolean isMainLog) {
495: boolean toStart = startStopTI.getImage().equals(imageStart);
496:
497: // starting log
498: if (toStart) {
499: // for main log, start all daemon threads
500: if (isMainLog) {
501: startAllLogs();
502: }
503: // for other log, start its daemon thread
504: else {
505: startSelectedLog(startStopTI);
506: }
507: }
508: // stopping log
509: else {
510: // for main log, stop all daemon threads
511: if (isMainLog) {
512: stopAllLogs();
513: }
514: // for other log, stop its daemon thread
515: else {
516: stopSelectedLog(startStopTI);
517: }
518: }
519: }
520:
521: private boolean hasStartStopImage(Image image) {
522: return image != null
523: && (image.equals(imageStart) || image.equals(imageStop));
524: }
525:
526: /**
527: * Removes all tab items from the tab folder.
528: */
529: private void removeTabItems() {
530: TabItem[] tabItems = tabFolder.getItems();
531: for (int i = 0; i < tabItems.length; ++i) {
532: tabItems[i].dispose();
533: }
534: }
535:
536: private void setupStartStopLogToolItem(List<ToolItem> startStopTIs,
537: boolean isStartState) {
538: for (int i = 0; i < startStopTIs.size(); ++i) {
539: ToolItem toolItem = startStopTIs.get(i);
540:
541: // first tool item is always the main log
542: setupStartStopLogToolItem(toolItem,
543: (i == 0) ? true : false, isStartState);
544: }
545: }
546:
547: private void setupStartStopLogToolItem(ToolItem toolItem,
548: boolean isMainLog, boolean isStartState) {
549: if (isStartState) {
550: toolItem.setImage(imageStop);
551: toolItem.setToolTipText(isMainLog ? "Stop All Logs"
552: : "Stop Log");
553: } else {
554: toolItem.setImage(imageStart);
555: toolItem.setToolTipText(isMainLog ? "Start All Logs"
556: : "Start Log");
557: }
558: }
559:
560: /**
561: * Sets up all tab items in the tab folder.
562: */
563: private void setupTabItems() {
564:
565: // setting up main tab
566: TabItem tabItem = new TabItem(tabFolder, SWT.NONE);
567:
568: Composite composite = createLogViewerComposite(true);
569:
570: tabItem.setControl(composite);
571: tabItem.setText(projectProperties.getMainTabItemName());
572:
573: // setting up other tabs based on the log configuration
574: for (int i = 0; i < logFiles.size(); ++i) {
575: final String tabItemName = logFiles.get(i).getLogName();
576:
577: composite = createLogViewerComposite(false);
578:
579: tabItem = new TabItem(tabFolder, SWT.NONE);
580: tabItem.setControl(composite);
581: tabItem.setText(tabItemName);
582: }
583:
584: tabFolder.pack();
585: }
586:
587: private void startAllLogs() {
588: destroyAllLogDaemons();
589: createAllLogDaemons();
590: setupStartStopLogToolItem(getAllStartStopLogToolItems(), true);
591: mediator
592: .handleEvent(ActionMediator.EVENT_UPDATE_GLOBAL_START_STOP_ICON);
593: }
594:
595: private void startSelectedLog(ToolItem toolItem) {
596: destroySelectedLogDaemon();
597: createSelectedLogDaemon();
598: setupStartStopLogToolItem(toolItem, false, true);
599: setupStartStopLogToolItem(getMainStartStopLogToolItem(), true,
600: true);
601: mediator
602: .handleEvent(ActionMediator.EVENT_UPDATE_GLOBAL_START_STOP_ICON);
603: }
604:
605: private void stopAllLogs() {
606: destroyAllLogDaemons();
607: setupStartStopLogToolItem(getAllStartStopLogToolItems(), false);
608: mediator
609: .handleEvent(ActionMediator.EVENT_UPDATE_GLOBAL_START_STOP_ICON);
610: }
611:
612: private void stopSelectedLog(ToolItem toolItem) {
613: destroySelectedLogDaemon();
614: setupStartStopLogToolItem(toolItem, false, false);
615: setupStartStopLogToolItem(getMainStartStopLogToolItem(), true,
616: false);
617: mediator
618: .handleEvent(ActionMediator.EVENT_UPDATE_GLOBAL_START_STOP_ICON);
619: }
620: }
|