| /* |
| * Copyright (c) 2012 Google Inc. |
| * |
| * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse |
| * Public License v1.0 which accompanies this distribution, and is available at |
| * |
| * http://www.eclipse.org/legal/epl-v10.html |
| */ |
| package com.google.eclipse.elt.view.ui; |
| |
| import com.google.eclipse.elt.emulator.control.ITerminalListener; |
| import com.google.eclipse.elt.emulator.provisional.api.TerminalState; |
| import com.google.eclipse.elt.view.Activator; |
| import com.google.eclipse.elt.view.ImageKeys; |
| import com.google.eclipse.elt.view.connector.LifeCycleListener; |
| import com.google.eclipse.elt.view.preferences.AbstractPreferencesChangeListener; |
| import com.google.eclipse.elt.view.preferences.ColorsAndFontsPreferences; |
| import com.google.eclipse.elt.view.preferences.GeneralPreferences; |
| |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IToolBarManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.dialogs.IInputValidator; |
| import org.eclipse.jface.dialogs.InputDialog; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.ISaveablePart2; |
| import org.eclipse.ui.IViewPart; |
| import org.eclipse.ui.IViewSite; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPartSite; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.contexts.IContextActivation; |
| import org.eclipse.ui.contexts.IContextService; |
| import org.eclipse.ui.part.ViewPart; |
| import org.eclipse.ui.progress.UIJob; |
| |
| import java.io.File; |
| import java.util.UUID; |
| |
| /** |
| * @author alruiz@google.com (Alex Ruiz) |
| */ |
| public class TerminalView extends ViewPart implements ISaveablePart2 { |
| private static final String SCROLL_LOCK_ENABLED = "scrollLock"; |
| private static final String TITLE_STATE_TYPE = "title"; |
| private static final String WORKING_DIRECTORY_STATE_TYPE = "workingDirectory"; |
| |
| private static final String VIEW_ID = "com.google.eclipse.terminal.local.localTerminalView"; |
| |
| private IPropertyChangeListener preferencesChangeListener; |
| private IPropertyChangeListener textFontChangeListener; |
| private IMemento savedState; |
| private TerminalWidget terminalWidget; |
| private IPath workingDirectory; |
| |
| private Action newTerminalAction; |
| private Action scrollLockAction; |
| |
| private boolean checkCanBeClosed; |
| private boolean forceClose; |
| |
| private IContextActivation contextActivation; |
| |
| /** |
| * Creates a new terminal view. |
| * |
| * @param workingDirectory the working directory to be opened on initialization |
| */ |
| public static void openTerminalView(IPath workingDirectory) { |
| openNewTerminalView(workingDirectory); |
| } |
| |
| /** |
| * Opens a new {@link TerminalView}. |
| * |
| * @param workingDirectory the working directory to be opened on initialization |
| */ |
| private static void openNewTerminalView(IPath workingDirectory) { |
| IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); |
| IPath safeWorkingDirectory = |
| (workingDirectory != null) ? workingDirectory : getDefaultWorkingDirectory(); |
| try { |
| String directoryName = safeWorkingDirectory.lastSegment(); |
| // Use of a freshTerminalId to force freshness of the identifier. |
| String secondaryId = UUID.randomUUID().toString(); |
| TerminalView view = |
| (TerminalView) page.showView(VIEW_ID, secondaryId, IWorkbenchPage.VIEW_ACTIVATE); |
| view.setPartName(directoryName); |
| view.open(safeWorkingDirectory); |
| } catch (PartInitException e) { |
| Activator.log("Unable to create Terminal View", e); |
| } |
| } |
| |
| @Override public void init(IViewSite site, IMemento memento) throws PartInitException { |
| super.init(site, memento); |
| savedState = memento; |
| } |
| |
| @Override public void saveState(IMemento memento) { |
| saveState(memento, SCROLL_LOCK_ENABLED, String.valueOf(terminalWidget.isScrollLockEnabled())); |
| saveState(memento, TITLE_STATE_TYPE, getPartName()); |
| if (workingDirectory != null) { |
| saveState(memento, WORKING_DIRECTORY_STATE_TYPE, workingDirectory.toOSString()); |
| } |
| } |
| |
| private void saveState(IMemento memento, String type, String data) { |
| IMemento child = memento.createChild(type); |
| child.putTextData(data); |
| } |
| |
| /** |
| * Returns a non-{@code null} directory to be used as the default working directory if one isn't |
| * explicitly provided. |
| */ |
| private static IPath getDefaultWorkingDirectory() { |
| File homeDirectory = new File(System.getProperty("user.home")); |
| if (homeDirectory.isDirectory()) { |
| return Path.fromOSString(homeDirectory.getAbsolutePath()); |
| } |
| File currentDirectory = new File(System.getProperty("user.dir")); |
| if (currentDirectory.isDirectory()) { |
| return Path.fromOSString(currentDirectory.getAbsolutePath()); |
| } |
| // If all else fails, pick the first root we can find. |
| for (File root : File.listRoots()) { |
| if (root.isDirectory()) { |
| return Path.fromOSString(root.getAbsolutePath()); |
| } |
| } |
| throw new IllegalStateException("Could not find valid working directory."); |
| } |
| |
| @Override public void createPartControl(Composite parent) { |
| terminalWidget = new TerminalWidget(parent, getViewSite()); |
| terminalWidget.setLifeCycleListener(new LifeCycleListener() { |
| @Override public void executionFinished() { |
| closeViewOnExitIfPossible(); |
| } |
| }); |
| terminalWidget.setTerminalListener(new ITerminalListener() { |
| @Override public void setTerminalTitle(final String title) { |
| updatePartName(title); |
| } |
| |
| @Override public void setState(TerminalState state) {} |
| }); |
| IViewSite viewSite = getViewSite(); |
| preferencesChangeListener = new AbstractPreferencesChangeListener() { |
| @Override protected void onBufferLineCountChanged() { |
| updateBufferLineCount(); |
| } |
| |
| @Override protected void onColorChanged() { |
| updateColors(); |
| } |
| |
| @Override protected void onFontChanged() { |
| updateFont(); |
| } |
| |
| @Override protected void onUseBlinkingCursorChanged() { |
| updateUsageOfBlinkingCursor(); |
| } |
| }; |
| Activator.preferenceStore().addPropertyChangeListener(preferencesChangeListener); |
| updateBufferLineCount(); |
| updateColors(); |
| updateUsageOfBlinkingCursor(); |
| textFontChangeListener = new IPropertyChangeListener() { |
| @Override public void propertyChange(PropertyChangeEvent event) { |
| if (JFaceResources.TEXT_FONT.equals(event.getProperty())) { |
| if (!ColorsAndFontsPreferences.useCustomFont()) { |
| setFont(JFaceResources.getTextFont()); |
| } |
| } |
| } |
| }; |
| JFaceResources.getFontRegistry().addListener(textFontChangeListener); |
| updateFont(); |
| setupToolBarActions(); |
| IContextService contextService = contextService(); |
| if (contextService != null) { |
| contextActivation = |
| contextService.activateContext("com.google.eclipse.terminal.local.context.localTerminal"); |
| } |
| if (savedState != null) { |
| updateScrollLockUsingSavedState(); |
| connectUsingSavedState(); |
| return; |
| } |
| if (viewSite.getSecondaryId() == null) { |
| setPartName(Messages.defaultViewTitle); |
| open(getDefaultWorkingDirectory()); |
| } |
| enableScrollLock(scrollLockAction.isChecked()); |
| } |
| |
| private void closeViewOnExitIfPossible() { |
| if (GeneralPreferences.closeViewOnExit() && terminalWidget != null |
| && !terminalWidget.isDisposed()) { |
| // must run in UI thread. |
| forceClose = true; |
| terminalWidget.getDisplay().asyncExec(new Runnable() { |
| @Override public void run() { |
| IWorkbenchPartSite site = getSite(); |
| site.getPage().hideView((IViewPart) site.getPart()); |
| } |
| }); |
| } |
| } |
| |
| private void updateColors() { |
| terminalWidget.setColors(ColorsAndFontsPreferences.background(), |
| ColorsAndFontsPreferences.foreground()); |
| } |
| |
| private void updateFont() { |
| setFont(terminalFont()); |
| } |
| |
| private void updateUsageOfBlinkingCursor() { |
| terminalWidget.setBlinkingCursor(ColorsAndFontsPreferences.useBlinkingCursor()); |
| } |
| |
| private Font terminalFont() { |
| if (ColorsAndFontsPreferences.useCustomFont()) { |
| return new Font(Display.getDefault(), ColorsAndFontsPreferences.customFontData()); |
| } |
| return JFaceResources.getTextFont(); |
| } |
| |
| private void setFont(Font font) { |
| terminalWidget.setFont(font); |
| } |
| |
| private void updateBufferLineCount() { |
| terminalWidget.setBufferLineCount(GeneralPreferences.bufferLineCount()); |
| } |
| |
| private void setupToolBarActions() { |
| IToolBarManager toolBarManager = getViewSite().getActionBars().getToolBarManager(); |
| toolBarManager.add(new ChangeViewNameAction()); |
| toolBarManager.add(new Separator()); |
| newTerminalAction = new NewTerminalAction(); |
| toolBarManager.add(newTerminalAction); |
| scrollLockAction = new ScrollLockAction(); |
| toolBarManager.add(scrollLockAction); |
| } |
| |
| private void updateScrollLockUsingSavedState() { |
| boolean newValue = Boolean.valueOf(savedState(SCROLL_LOCK_ENABLED)); |
| enableScrollLockAndUpdateAction(newValue); |
| } |
| |
| private void enableScrollLockAndUpdateAction(boolean enabled) { |
| enableScrollLock(enabled); |
| scrollLockAction.setChecked(enabled); |
| } |
| |
| private void enableScrollLock(boolean enabled) { |
| terminalWidget.enableScrollLock(enabled); |
| } |
| |
| private void connectUsingSavedState() { |
| String title = savedState(TITLE_STATE_TYPE); |
| setPartName(title); |
| String savedWorkingDirectory = savedState(WORKING_DIRECTORY_STATE_TYPE); |
| if (savedWorkingDirectory == null) { |
| open(getDefaultWorkingDirectory()); |
| } else { |
| open(Path.fromOSString(savedWorkingDirectory)); |
| } |
| } |
| |
| private String savedState(String type) { |
| IMemento child = savedState.getChild(type); |
| return (child != null) ? child.getTextData() : null; |
| } |
| |
| private void open(IPath workingDirectory) { |
| // workingDirectory should be non-null. |
| if (terminalWidget.isConnected()) { |
| return; |
| } |
| this.workingDirectory = workingDirectory; |
| terminalWidget.setWorkingDirectory(workingDirectory); |
| terminalWidget.connect(); |
| } |
| |
| private void updatePartName(final String value) { |
| UIJob job = new UIJob("Update terminal view title") { |
| @Override public IStatus runInUIThread(IProgressMonitor monitor) { |
| setPartName(value); |
| return Status.OK_STATUS; |
| } |
| }; |
| job.schedule(); |
| } |
| |
| @Override public void setFocus() { |
| terminalWidget.setFocus(); |
| } |
| |
| @Override public void dispose() { |
| if (contextActivation != null) { |
| IContextService contextService = contextService(); |
| if (contextService != null) { |
| contextService.deactivateContext(contextActivation); |
| } |
| } |
| if (preferencesChangeListener != null) { |
| Activator.preferenceStore().removePropertyChangeListener(preferencesChangeListener); |
| } |
| if (textFontChangeListener != null) { |
| JFaceResources.getFontRegistry().removeListener(textFontChangeListener); |
| } |
| super.dispose(); |
| } |
| |
| private IContextService contextService() { |
| return (IContextService) getSite().getService(IContextService.class); |
| } |
| |
| @Override public boolean isDirty() { |
| if (checkCanBeClosed) { |
| checkCanBeClosed = false; |
| return true; |
| } |
| return false; |
| } |
| |
| @Override public boolean isSaveOnCloseNeeded() { |
| if (forceClose) { |
| return false; |
| } |
| checkCanBeClosed = true; |
| return true; |
| } |
| |
| @Override public int promptToSaveOnClose() { |
| if (GeneralPreferences.warnOnClose()) { |
| boolean close = WarnOnCloseDialog.open(terminalWidget.getShell()); |
| if (!close) { |
| return CANCEL; |
| } |
| } |
| return NO; |
| } |
| |
| @Override public void doSave(IProgressMonitor monitor) {} |
| |
| @Override public void doSaveAs() {} |
| |
| @Override public boolean isSaveAsAllowed() { |
| return false; |
| } |
| |
| private class NewTerminalAction extends Action { |
| NewTerminalAction() { |
| setImageDescriptor(Activator.imageDescriptor(ImageKeys.NEW_TERMINAL)); |
| setText(Messages.newLocalTerminal); |
| } |
| |
| @Override public void run() { |
| openNewTerminalView(workingDirectory); |
| } |
| } |
| |
| private class ScrollLockAction extends Action { |
| ScrollLockAction() { |
| super(Messages.scrollLock, AS_RADIO_BUTTON); |
| setChecked(false); |
| setImageDescriptor(Activator.imageDescriptor(ImageKeys.SCROLL_LOCK)); |
| } |
| |
| @Override public void run() { |
| boolean newValue = !terminalWidget.isScrollLockEnabled(); |
| enableScrollLockAndUpdateAction(newValue); |
| } |
| } |
| |
| private class ChangeViewNameAction extends Action { |
| ChangeViewNameAction() { |
| setImageDescriptor(Activator.imageDescriptor(ImageKeys.CHANGE_TITLE)); |
| setText(Messages.changeTerminalTitle); |
| } |
| |
| @Override public void run() { |
| Shell shell = getViewSite().getShell(); |
| final String currentTitle = getPartName(); |
| InputDialog input = new InputDialog(shell, Messages.enterTerminalTitleDialogTitle, |
| Messages.enterTerminalTitlePrompt, currentTitle, |
| new IInputValidator() { |
| @Override public String isValid(String newText) { |
| if (newText == null || newText.isEmpty() || currentTitle.equals(newText)) { |
| return ""; |
| } |
| return null; |
| } |
| }); |
| input.setBlockOnOpen(true); |
| if (input.open() == Window.OK) { |
| setPartName(input.getValue()); |
| } |
| } |
| } |
| } |