From 61ac5642e903398c1db7e3e1d99e52f301d7d74d Mon Sep 17 00:00:00 2001 From: Andrew Gvozdev Date: Tue, 19 Oct 2010 15:40:17 +0000 Subject: [PATCH] bug 309113: Ability to have a single build console for a multi-project build Patch from Alex Collins (with a few improvements) --- .../org/eclipse/cdt/make/ui/TargetBuild.java | 4 + .../actions/BuildAllConfigurationsAction.java | 4 + .../ui/actions/BuildConfigurationsJob.java | 4 + .../actions/CleanAllConfigurationsAction.java | 4 + core/org.eclipse.cdt.ui/plugin.properties | 1 + core/org.eclipse.cdt.ui/plugin.xml | 17 +++ .../ui/buildconsole/BuildConsole.java | 19 ++- .../ui/buildconsole/BuildConsoleManager.java | 126 +++++++++++++++--- .../ui/buildconsole/BuildConsolePage.java | 41 ++++-- .../BuildConsolePageParticipant.java | 41 ++++++ .../buildconsole/BuildConsolePartitioner.java | 55 ++++++-- .../ui/buildconsole/BuildConsoleViewer.java | 2 +- .../ui/buildconsole/BuildOutputStream.java | 8 +- .../ui/buildconsole/ConsoleMessages.java | 1 + .../buildconsole/ConsoleMessages.properties | 2 + .../ui/buildconsole/CopyBuildLogAction.java | 15 ++- .../ui/buildconsole/GlobalBuildConsole.java | 28 ++++ .../MultiBuildConsoleAdapter.java | 95 +++++++++++++ .../ui/buildconsole/ShowErrorAction.java | 19 ++- .../cdt/internal/ui/cview/BuildGroup.java | 6 + .../preferences/BuildLogPreferencePage.java | 1 + .../GlobalBuildLogPreferencePage.java | 75 +++++++++++ .../ui/preferences/PreferencesMessages.java | 2 + .../PreferencesMessages.properties | 4 + .../eclipse/cdt/ui/IBuildConsoleManager.java | 36 +++++ 25 files changed, 552 insertions(+), 58 deletions(-) create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePageParticipant.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/GlobalBuildConsole.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/MultiBuildConsoleAdapter.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/GlobalBuildLogPreferencePage.java diff --git a/build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/ui/TargetBuild.java b/build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/ui/TargetBuild.java index e53aa256d64..536c118ca1e 100644 --- a/build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/ui/TargetBuild.java +++ b/build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/ui/TargetBuild.java @@ -17,6 +17,7 @@ import java.util.List; import org.eclipse.cdt.make.core.IMakeTarget; import org.eclipse.cdt.make.internal.ui.MakeUIPlugin; import org.eclipse.cdt.make.internal.ui.preferences.MakePreferencePage; +import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRunnable; @@ -87,6 +88,9 @@ public class TargetBuild { } static public void buildTargets(Shell shell, final IMakeTarget[] targets) { + // Setup the global build console + CUIPlugin.getDefault().getConsoleManager().startGlobalConsole(); + saveAllResources(targets); Job targetJob = new Job(MakeUIPlugin.getResourceString("TargetBuild.backgroundTask.name")) { //$NON-NLS-1$ @Override diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/actions/BuildAllConfigurationsAction.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/actions/BuildAllConfigurationsAction.java index 30a30b15063..7e7901d3b09 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/actions/BuildAllConfigurationsAction.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/actions/BuildAllConfigurationsAction.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; +import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.runtime.jobs.Job; @@ -36,6 +37,9 @@ public class BuildAllConfigurationsAction implements IObjectActionDelegate { } public void run(IAction action) { + // Setup the global build console + CUIPlugin.getDefault().getConsoleManager().startGlobalConsole(); + for (IProject project : projects) { ICProjectDescription prjd = CoreModel.getDefault().getProjectDescription(project, false); if (prjd != null) { diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/actions/BuildConfigurationsJob.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/actions/BuildConfigurationsJob.java index 7f73fc11c05..6e9ddb0f29d 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/actions/BuildConfigurationsJob.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/actions/BuildConfigurationsJob.java @@ -14,6 +14,7 @@ import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.internal.ui.Messages; +import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -67,6 +68,9 @@ public class BuildConfigurationsJob extends Job { */ @Override protected IStatus run(IProgressMonitor monitor) { + // Setup the global build console + CUIPlugin.getDefault().getConsoleManager().startGlobalConsole(); + IConfiguration[] cfgs = new IConfiguration[cfgDescriptions.length]; for (int i=0; i + + + + + + + + + + fConsoleMap = new HashMap(); private Color infoColor; private Color outputColor; @@ -132,7 +145,7 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang /** * Opens the console view. If the view is already open, it is brought to the - * front. + * front. The console that is shown is the console that was last on top. */ protected void showConsole() { IWorkbenchWindow window = CUIPlugin.getActiveWorkbenchWindow(); @@ -157,7 +170,10 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang } } if (consoleView instanceof IConsoleView) { - ((IConsoleView)consoleView).display(fConsole); + if (BuildConsole.getCurrentPage() == null) + ((IConsoleView)consoleView).display(fGlobalConsole); + else + ((IConsoleView)consoleView).display(BuildConsole.getCurrentPage().getConsole()); } } } @@ -209,7 +225,7 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang problemInfoBackgroundColor.dispose(); problemHighlightedColor.dispose(); } - ConsolePlugin.getDefault().getConsoleManager().removeConsoles(new org.eclipse.ui.console.IConsole[]{fConsole}); + ConsolePlugin.getDefault().getConsoleManager().removeConsoles(new org.eclipse.ui.console.IConsole[]{fGlobalConsole, fConsole}); CUIPlugin.getWorkspace().removeResourceChangeListener(this); CUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this); } @@ -241,8 +257,9 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang */ public void run() { // install colors + fGlobalConsole = new GlobalBuildConsole(BuildConsoleManager.this, fName, null); fConsole = new BuildConsole(BuildConsoleManager.this, fName, fContextMenuId); - ConsolePlugin.getDefault().getConsoleManager().addConsoles(new org.eclipse.ui.console.IConsole[]{fConsole}); + ConsolePlugin.getDefault().getConsoleManager().addConsoles(new org.eclipse.ui.console.IConsole[]{fGlobalConsole, fConsole}); infoStream.setConsole(fConsole); infoColor = createColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_INFO_COLOR); infoStream.setColor(infoColor); @@ -254,6 +271,7 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang errorStream.setColor(errorColor); backgroundColor = createBackgroundColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_BACKGROUND_COLOR); fConsole.setBackground(backgroundColor); + fGlobalConsole.setBackground(backgroundColor); problemHighlightedColor = createColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_PROBLEM_HIGHLIGHTED_COLOR); problemErrorBackgroundColor = createBackgroundColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_PROBLEM_BACKGROUND_COLOR); problemWarningBackgroundColor = createBackgroundColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_PROBLEM_WARNING_BACKGROUND_COLOR); @@ -290,6 +308,7 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang } else if (property.equals(BuildConsolePreferencePage.PREF_BUILDCONSOLE_BACKGROUND_COLOR)) { Color newColor = createBackgroundColor(CUIPlugin.getStandardDisplay(), BuildConsolePreferencePage.PREF_BUILDCONSOLE_BACKGROUND_COLOR); fConsole.setBackground(newColor); + fGlobalConsole.setBackground(newColor); backgroundColor.dispose(); backgroundColor = newColor; } else if (property.equals(BuildConsolePreferencePage.PREF_BUILDCONSOLE_PROBLEM_HIGHLIGHTED_COLOR)) { @@ -316,7 +335,7 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang } private void redrawTextViewer() { - final BuildConsolePage p = BuildConsole.getPage(); + final BuildConsolePage p = BuildConsole.getCurrentPage(); if ( p == null ) return; final BuildConsoleViewer v = p.getViewer(); if ( v == null ) return; @@ -367,9 +386,23 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang * Returns the console for the project, or null if none. */ public IConsole getConsole(IProject project) { + return new MultiBuildConsoleAdapter(getProjectConsole(project), getGlobalConsole()); + } + + /** + * @return the console for the specified project + */ + public IConsole getProjectConsole(IProject project) { Assert.isNotNull(project); fLastProject = project; - return getConsolePartioner(project).getConsole(); + return getProjectConsolePartioner(project).getConsole(); + } + + /** + * @return the global build console + */ + public IConsole getGlobalConsole() { + return getGlobalConsolePartitioner().getConsole(); } /* @@ -380,23 +413,57 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang public IProject getLastBuiltProject() { return fLastProject; } - - private BuildConsolePartitioner getConsolePartioner(IProject project) { - BuildConsolePartitioner partioner = fConsoleMap.get(project); - if (partioner == null) { - partioner = new BuildConsolePartitioner(project, this); - fConsoleMap.put(project, partioner); + + /** + * @return the partitioner for the specified projects build console + */ + private BuildConsolePartitioner getProjectConsolePartioner(IProject project) { + BuildConsolePartitioner partitioner = fConsoleMap.get(project); + if (partitioner == null) { + partitioner = new BuildConsolePartitioner(project, this); + fConsoleMap.put(project, partitioner); } - return partioner; + return partitioner; } /** - * Returns the document for the projects console, or null if - * none. + * @return the partitioner for the global build console + */ + private BuildConsolePartitioner getGlobalConsolePartitioner() { + if (fGlobalConsolePartitioner == null) + fGlobalConsolePartitioner = new BuildConsolePartitioner(this); + return fGlobalConsolePartitioner; + } + + /** + * Start the global console; called at the start of the build. + * Clears the contents of the console and sets up the log output stream. + */ + public void startGlobalConsole() { + if (BuildConsolePreferencePage.isClearBuildConsole()) + getGlobalConsolePartitioner().appendToDocument("", null, null); //$NON-NLS-1$ + getGlobalConsolePartitioner().setStreamOpened(); + } + + public void stopGlobalConsole() { + // Doesn't do anything currently. This would be a cleaner place to close the global console + // log, but there is nowhere in CDT that can invoke it at the end of the entire build. + // Instead, the log is repeatedly closed and opened for append by each project build. + } + + /** + * @return the document backing the build console for the specified project */ public IDocument getConsoleDocument(IProject project) { Assert.isNotNull(project); - return getConsolePartioner(project).getDocument(); + return getProjectConsolePartioner(project).getDocument(); + } + + /** + * @return the document backing the global build console + */ + public IDocument getGlobalConsoleDocument() { + return getGlobalConsolePartitioner().getDocument(); } public void addConsoleListener(IBuildConsoleListener listener) { @@ -408,19 +475,34 @@ public class BuildConsoleManager implements IBuildConsoleManager, IResourceChang } /** - * @return logging preferences for a given project. - * @param project to get logging preferences for. + * @return logging preferences for a given project or for the workspace. + * @param project to get logging preferences for; or null for the workspace. */ public static Preferences getBuildLogPreferences(IProject project) { - return new LocalProjectScope(project).getNode(QUALIFIER).node(BUILD_CONSOLE_NODE); + if (project == null) + return new InstanceScope().getNode(QUALIFIER).node(GLOBAL_BUILD_CONSOLE_NODE); + else + return new LocalProjectScope(project).getNode(QUALIFIER).node(BUILD_CONSOLE_NODE); } /** - * @return default location of logs for a project. - * @param project to get default log location for. + * @return logging preference store for a given project; or for the workspace. + * @param project to get logging preferences for; or null for the workspace. + */ + public static IPreferenceStore getBuildLogPreferenceStore(IProject project) { + if (project == null) + return new ScopedPreferenceStore(new InstanceScope(), QUALIFIER + "/" + GLOBAL_BUILD_CONSOLE_NODE); //$NON-NLS-1$ + else + return new ScopedPreferenceStore(new LocalProjectScope(project), QUALIFIER + "/" + BUILD_CONSOLE_NODE); //$NON-NLS-1$ + } + + /** + * @return default location of logs for a project or for the workspace. + * @param project to get default log location for; or null for the workspace. */ public static String getDefaultConsoleLogLocation(IProject project) { - IPath defaultLogLocation = CUIPlugin.getDefault().getStateLocation().append(project.getName()+".build.log"); //$NON-NLS-1$ + String name = project == null ? GLOBAL_LOG_FILE : project.getName() + PROJECT_LOG_EXT; + IPath defaultLogLocation = CUIPlugin.getDefault().getStateLocation().append(name); return defaultLogLocation.toOSString(); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePage.java index 0ef40d27c0e..43479a815b8 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePage.java @@ -10,6 +10,7 @@ * Red Hat Inc. - multiple build console support * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation * Save build output + * Alex Collins (Broadcom Corp.) - Global build console *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; @@ -162,11 +163,21 @@ public class BuildConsolePage extends Page IProject project = getProject(); if (project != null) { IBuildConsoleManager consoleManager = getConsole().getConsoleManager(); - getViewer().setDocument(consoleManager.getConsoleDocument(project)); - IConsole console = consoleManager.getConsole(project); - if ( console instanceof BuildConsolePartitioner) { + IDocument document; + IConsole console; + if (getConsole() instanceof GlobalBuildConsole) { + document = consoleManager.getGlobalConsoleDocument(); + console = consoleManager.getGlobalConsole(); + } else { + document = consoleManager.getConsoleDocument(project); + console = consoleManager.getProjectConsole(project); + } + getViewer().setDocument(document); + if (console instanceof BuildConsolePartitioner) { BuildConsolePartitioner par = (BuildConsolePartitioner)console; - showError(par, fShowErrorAction.isChecked() ); + // Show the error, but don't show it in the editor if we are viewing the global console. + // Prevents showing errors in the editor for projects other than the current project. + showError(par, fShowErrorAction.isChecked() && !(getConsole() instanceof GlobalBuildConsole)); } } return null; @@ -548,17 +559,27 @@ public class BuildConsolePage extends Page } } + /** + * Get the current CDT IConsole being displayed on the page + */ + private IConsole getCurrentConsole() { + BuildConsoleManager consoleManager = (BuildConsoleManager)CUIPlugin.getDefault().getConsoleManager(); + if (getConsole() instanceof GlobalBuildConsole) + return consoleManager.getGlobalConsole(); + else if (getProject() == null) + return null; + else + return consoleManager.getProjectConsole(getProject()); + } + /** * Highlight next/previous error or error by console offset * @param position POSITION_NEXT (-1), POSITION_PREV (-2), or offset */ void moveToError(int position) { - IProject project = getProject(); - if (project == null) return; - - IBuildConsoleManager consoleManager = CUIPlugin.getDefault().getConsoleManager(); - IConsole console = consoleManager.getConsole(project); - if ( console instanceof BuildConsolePartitioner) { + IConsole console = getCurrentConsole(); + if (console == null) return; + if (console instanceof BuildConsolePartitioner) { BuildConsolePartitioner par = (BuildConsolePartitioner)console; // Move to specified line in the model (BuildConsolePartitioner) if ( position == POSITION_NEXT ) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePageParticipant.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePageParticipant.java new file mode 100644 index 00000000000..774f6e82b46 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePageParticipant.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2010 Broadcom Corporation and others. + * 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 + * + * Contributors: + * Alex Collins (Broadcom Corp.) - Initial implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.buildconsole; + +import org.eclipse.ui.console.IConsole; +import org.eclipse.ui.console.IConsolePageParticipant; +import org.eclipse.ui.part.IPageBookViewPage; + +/** + * Attached to extension point org.eclipse.ui.console.consolePageParticipants to notify + * BuildConsole that a new page has become visible. + */ +public class BuildConsolePageParticipant implements IConsolePageParticipant { + private BuildConsole console; + + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + return null; + } + + public void init(IPageBookViewPage page, IConsole console) { + this.console = (BuildConsole)console; + } + + public void dispose() { + } + + public void activated() { + BuildConsole.setCurrentPage(console.getPage()); + } + + public void deactivated() { + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java index a6f79f721f2..2f987028d13 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsolePartitioner.java @@ -9,6 +9,7 @@ * QNX Software Systems - initial API and implementation * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation * Andrew Gvozdev (Quoin Inc.) - Copy build log (bug 306222) + * Alex Collins (Broadcom Corp.) - Global console *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; @@ -90,6 +91,7 @@ public class BuildConsolePartitioner static public final int EVENT_APPEND = 0; static public final int EVENT_OPEN_LOG = 1; static public final int EVENT_CLOSE_LOG = 2; + static public final int EVENT_OPEN_APPEND_LOG = 3; /** Identifier of the stream written to. */ private BuildConsoleStreamDecorator fStream; @@ -157,6 +159,13 @@ public class BuildConsolePartitioner } + /** + * Construct a partitioner that is not associated with a specific project + */ + public BuildConsolePartitioner(BuildConsoleManager manager) { + this(null, manager); + } + public BuildConsolePartitioner(IProject project, BuildConsoleManager manager) { fProject = project; fManager = manager; @@ -179,6 +188,16 @@ public class BuildConsolePartitioner asyncProcessQueue(); } + /** + * Open the stream for appending. Must be called after a call to setStreamOpened(). + * Can be used to reopen a stream for writing after it has been closed, without + * emptying the log file. + */ + public void setStreamAppend() { + fQueue.add(new StreamEntry(StreamEntry.EVENT_OPEN_APPEND_LOG)); + asyncProcessQueue(); + } + /** * Sets the indicator that stream was closed so logging should be stopped. Should be called when * build process has finished. Note that there could still be unprocessed console @@ -240,7 +259,7 @@ public class BuildConsolePartitioner /** * Asynchronous processing of stream entries to append to console. - * Note that all these are processed by the same by the user-interface thread + * Note that all these are processed by the same thread - the user-interface thread * as of {@link Display#asyncExec(Runnable)}. */ private void asyncProcessQueue() { @@ -254,7 +273,8 @@ public class BuildConsolePartitioner } switch (entry.getEventType()) { case StreamEntry.EVENT_OPEN_LOG: - logOpen(); + case StreamEntry.EVENT_OPEN_APPEND_LOG: + logOpen(entry.getEventType() == StreamEntry.EVENT_OPEN_APPEND_LOG); break; case StreamEntry.EVENT_APPEND: fLastStream = entry.getStream(); @@ -267,9 +287,12 @@ public class BuildConsolePartitioner fDocumentMarkerManager.clear(); fDocument.set(""); //$NON-NLS-1$ } - addStreamEntryToDocument(entry); - log(entry.getText()); - checkOverflow(); + String text = entry.getText(); + if (text.length()>0) { + addStreamEntryToDocument(entry); + log(text); + checkOverflow(); + } } catch (BadLocationException e) { } break; @@ -278,12 +301,22 @@ public class BuildConsolePartitioner break; } } - private void logOpen() { + + /** + * Open the log + * @param append Set to true if the log should be opened for appending, false for overwriting. + */ + private void logOpen(boolean append) { fLogURI = getLogURI(fProject); if (fLogURI!=null) { try { IFileStore logStore = EFS.getStore(fLogURI); - fLogStream = logStore.openOutputStream(EFS.NONE, null); + // Ensure the directory exists before opening the file + IFileStore dir = logStore.getParent(); + if (dir != null) + dir.mkdir(EFS.NONE, null); + int opts = append ? EFS.APPEND : EFS.NONE; + fLogStream = logStore.openOutputStream(opts, null); } catch (CoreException e) { CUIPlugin.log(e); } finally { @@ -557,13 +590,13 @@ public class BuildConsolePartitioner if (display != null) { display.asyncExec(new Runnable() { public void run() { + fLogStream = null; + fLogURI = null; fManager.startConsoleActivity(project); } }); } - fLogURI = null; - fLogStream = null; if (BuildConsolePreferencePage.isClearBuildConsole()) { appendToDocument("", null, null); //$NON-NLS-1$ @@ -620,4 +653,8 @@ public class BuildConsolePartitioner public URI getLogURI() { return fLogURI; } + + IProject getProject() { + return fProject; + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleViewer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleViewer.java index 014b5dc6423..7b309e6230a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleViewer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildConsoleViewer.java @@ -239,7 +239,7 @@ public class BuildConsoleViewer extends TextViewer try { Point p = new Point(e.x, e.y); offset = getTextWidget().getOffsetAtLocation(p); - BuildConsole.getPage().moveToError(offset); + BuildConsole.getCurrentPage().moveToError(offset); } catch (IllegalArgumentException ex) { } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java index b61f1245f87..a5ce0891a46 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/BuildOutputStream.java @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - initial API and implementation * Dmitry Kozlov (CodeSourcery) - Build error highlighting and navigation + * Alex Collins (Broadcom Corp.) - Global build console *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; @@ -31,7 +32,12 @@ public class BuildOutputStream extends ConsoleOutputStream implements IErrorMark public BuildOutputStream(BuildConsolePartitioner partitioner, BuildConsoleStreamDecorator stream) { fPartitioner = partitioner; - fPartitioner.setStreamOpened(); + if (fPartitioner.getProject() == null) + // Note: The global console log stream should have been + // opened by BuildConsoleManager.startGlobalConsole() + fPartitioner.setStreamAppend(); + else + fPartitioner.setStreamOpened(); fStream = stream; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.java index bfdc1ab9a92..a144869ee3b 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.java @@ -22,6 +22,7 @@ public final class ConsoleMessages extends NLS { // Do not instantiate } + public static String BuildConsole_GlobalConsole; public static String find_replace_action_label; public static String find_replace_action_tooltip; public static String find_replace_action_image; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.properties index 64a1f716584..352bc5389ab 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ConsoleMessages.properties @@ -10,6 +10,8 @@ # IBM Corporation ############################################################################### +BuildConsole_GlobalConsole=CDT Global Build Console + find_replace_action_label=&Find/Replace...@Ctrl+F find_replace_action_tooltip=Find/Replace find_replace_action_image= diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/CopyBuildLogAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/CopyBuildLogAction.java index 69814d41c2f..0691f0ca7f1 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/CopyBuildLogAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/CopyBuildLogAction.java @@ -7,6 +7,7 @@ * * Contributors: * Andrew Gvozdev (Quoin Inc.) - Initial API and implementation + * Alex Collins (Broadcom Corp.) - Global console *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; @@ -46,13 +47,17 @@ public class CopyBuildLogAction extends Action { @Override public void run() { - IProject project = fConsolePage.getProject(); - if (project == null || !project.isAccessible()) - return; - IBuildConsoleManager consoleManager = CUIPlugin.getDefault().getConsoleManager(); + IConsole console; + if (fConsolePage.getConsole() instanceof GlobalBuildConsole) + console = consoleManager.getGlobalConsole(); + else { + IProject project = fConsolePage.getProject(); + if (project == null || !project.isAccessible()) + return; + console = consoleManager.getProjectConsole(project); + } - IConsole console = consoleManager.getConsole(project); if (console instanceof BuildConsolePartitioner) { Shell shell = Display.getCurrent().getActiveShell(); URI srcURI = ((BuildConsolePartitioner)console).getLogURI(); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/GlobalBuildConsole.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/GlobalBuildConsole.java new file mode 100644 index 00000000000..15c598f9d73 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/GlobalBuildConsole.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2010 Broadcom Corporation and others. + * 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 + * + * Contributors: + * Alex Collins (Broadcom Corp.) + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.buildconsole; + +import org.eclipse.cdt.ui.IBuildConsoleManager; +import org.eclipse.core.resources.IProject; + +/** + * Customised BuildConsole for the global console that displays its title differently + */ +public class GlobalBuildConsole extends BuildConsole { + public GlobalBuildConsole(IBuildConsoleManager manager, String name, String id) { + super(manager, name, id); + setName(ConsoleMessages.BuildConsole_GlobalConsole); + } + + @Override + public void setTitle(IProject project) { + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/MultiBuildConsoleAdapter.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/MultiBuildConsoleAdapter.java new file mode 100644 index 00000000000..86769c03fcc --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/MultiBuildConsoleAdapter.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2010 Broadcom Corporation and others. + * 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 + * + * Contributors: + * Alex Collins (Broadcom Corp.) + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.buildconsole; + +import java.io.IOException; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.cdt.core.ConsoleOutputStream; +import org.eclipse.cdt.core.ProblemMarkerInfo; +import org.eclipse.cdt.core.resources.IConsole; + +import org.eclipse.cdt.internal.core.IErrorMarkeredOutputStream; + +/** + * Adapter that wraps a project console and the global console to allow builders + * to send their build output to a single IConsole object + */ +class MultiBuildConsoleAdapter implements IConsole { + + private final IConsole fProjectConsole; + private final IConsole fGlobalConsole; + + private static class BuildOutputStreamAdapter extends ConsoleOutputStream implements IErrorMarkeredOutputStream { + private final BuildOutputStream one; + private final BuildOutputStream two; + + public BuildOutputStreamAdapter(BuildOutputStream one, BuildOutputStream two) { + this.one = one; + this.two = two; + } + + @Override + public synchronized String readBuffer() { + return one.readBuffer(); + } + + @Override + public synchronized void write(int c) throws IOException { + one.write(c); + two.write(c); + } + + @Override + public synchronized void write(byte[] b, int off, int len) throws IOException { + one.write(b, off, len); + two.write(b, off, len); + } + + public void write(String s, ProblemMarkerInfo marker) throws IOException { + one.write(s, marker); + two.write(s, marker); + } + + @Override + public void close() throws IOException { + one.flush(); + two.flush(); + one.close(); + two.close(); + } + + } + + public MultiBuildConsoleAdapter(IConsole projectConsole, IConsole globalConsole) { + fProjectConsole = projectConsole; + fGlobalConsole = globalConsole; + } + + public void start(IProject project) { + fProjectConsole.start(project); + } + + public ConsoleOutputStream getOutputStream() throws CoreException { + return new BuildOutputStreamAdapter((BuildOutputStream)fProjectConsole.getOutputStream(), (BuildOutputStream)fGlobalConsole.getOutputStream()); + } + + public ConsoleOutputStream getInfoStream() throws CoreException { + return new BuildOutputStreamAdapter((BuildOutputStream)fProjectConsole.getInfoStream(), (BuildOutputStream)fGlobalConsole.getInfoStream()); + } + + public ConsoleOutputStream getErrorStream() throws CoreException { + return new BuildOutputStreamAdapter((BuildOutputStream)fProjectConsole.getErrorStream(), (BuildOutputStream)fGlobalConsole.getErrorStream()); + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ShowErrorAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ShowErrorAction.java index 51f3ed33c8e..923a7b4abe4 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ShowErrorAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/buildconsole/ShowErrorAction.java @@ -7,6 +7,7 @@ * * Contributors: * Dmitry Kozlov (CodeSourcery) - Initial API and implementation + * Alex Collins (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.ui.buildconsole; @@ -43,15 +44,19 @@ public class ShowErrorAction extends Action { @Override public void run() { super.run(); - if ( isChecked() ) { - IProject project = fConsolePage.getProject(); - if (project == null) return; - + if (isChecked()) { IBuildConsoleManager consoleManager = CUIPlugin.getDefault().getConsoleManager(); - IConsole console = consoleManager.getConsole(project); - if ( console instanceof BuildConsolePartitioner) { + IProject project = fConsolePage.getProject(); + IConsole console; + if (fConsolePage.getConsole() instanceof GlobalBuildConsole) + console = consoleManager.getGlobalConsole(); + else if (project == null) + return; + else + console = consoleManager.getProjectConsole(project); + if (console instanceof BuildConsolePartitioner) { BuildConsolePartitioner par = (BuildConsolePartitioner)console; - fConsolePage.showError(par, true ); + fConsolePage.showError(par, true); } } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/cview/BuildGroup.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/cview/BuildGroup.java index 705e39b9739..3d476d8a58a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/cview/BuildGroup.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/cview/BuildGroup.java @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Alex Collins (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.ui.cview; @@ -40,6 +41,8 @@ import org.eclipse.ui.actions.BuildAction; import org.eclipse.ui.ide.IDEActionFactory; import org.eclipse.ui.ide.ResourceUtil; +import org.eclipse.cdt.ui.CUIPlugin; + /** * This is the action group for workspace actions such as Build */ @@ -76,6 +79,9 @@ public class BuildGroup extends CViewActionGroup { } saveEditors(prjs); + // Clear the build console, and open a stream + CUIPlugin.getDefault().getConsoleManager().startGlobalConsole(); + // Now delegate to the parent super.run(); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/BuildLogPreferencePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/BuildLogPreferencePage.java index f92add233e6..77d4f53e896 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/BuildLogPreferencePage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/BuildLogPreferencePage.java @@ -61,6 +61,7 @@ public class BuildLogPreferencePage extends PropertyPage implements ICOptionCont // [v] Enable Logging enableLoggingCheckbox = ControlFactory.createCheckBox(contents, PreferencesMessages.BuildLogPreferencePage_EnableLogging); + ((GridData) enableLoggingCheckbox.getLayoutData()).horizontalSpan = 2; boolean keepLog = prefs.getBoolean(BuildConsoleManager.KEY_KEEP_LOG, BuildConsoleManager.CONSOLE_KEEP_LOG_DEFAULT); enableLoggingCheckbox.setSelection(keepLog); enableLoggingCheckbox.addSelectionListener(new SelectionAdapter() { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/GlobalBuildLogPreferencePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/GlobalBuildLogPreferencePage.java new file mode 100644 index 00000000000..2df5181dd3d --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/GlobalBuildLogPreferencePage.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2010 Broadcom Corporation and others. + * 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 + * + * Contributors: + * Alex Collins (Broadcom Corp.) - Initial implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.preferences; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.StringButtonFieldEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +import org.eclipse.cdt.internal.ui.buildconsole.BuildConsoleManager; + +/** + * Preference page for build logging options, such as whether the + * global build console should be logged and, if so, where. + */ +public class GlobalBuildLogPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { + public GlobalBuildLogPreferencePage() { + super(GRID); + setPreferenceStore(BuildConsoleManager.getBuildLogPreferenceStore(null)); + } + + /** + * A file path field with choose button that does not require the chosen file to exist. + */ + static private class FilePathEditor extends StringButtonFieldEditor { + public FilePathEditor(String name, String label, Composite parent) { + super(name, label, parent); + } + + @Override + protected String changePressed() { + FileDialog dialog = new FileDialog(getShell(), SWT.NONE); + dialog.setText(getLabelText()); + String fileName = super.oldValue; + IPath logFolder = new Path(fileName).removeLastSegments(1); + dialog.setFilterPath(logFolder.toOSString()); + return dialog.open(); + } + } + + @Override + protected void createFieldEditors() { + Composite parent = getFieldEditorParent(); + BooleanFieldEditor keepLog = new BooleanFieldEditor(BuildConsoleManager.KEY_KEEP_LOG, + PreferencesMessages.GlobalBuildLogPreferencePage_EnableLogging, parent); + addField(keepLog); + FilePathEditor logLocation = new FilePathEditor(BuildConsoleManager.KEY_LOG_LOCATION, + PreferencesMessages.GlobalBuildLogPreferencePage_LogLocation, parent); + addField(logLocation); + } + + public void init(IWorkbench workbench) { + initDefaults(BuildConsoleManager.getBuildLogPreferenceStore(null)); + } + + public static void initDefaults(IPreferenceStore prefs) { + prefs.setDefault(BuildConsoleManager.KEY_KEEP_LOG, BuildConsoleManager.CONSOLE_KEEP_LOG_DEFAULT); + prefs.setDefault(BuildConsoleManager.KEY_LOG_LOCATION, BuildConsoleManager.getDefaultConsoleLogLocation(null)); + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java index 04657ad4a95..c99f011a446 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.java @@ -149,6 +149,8 @@ public final class PreferencesMessages extends NLS { public static String BuildLogPreferencePage_ChooseLogFile; public static String BuildLogPreferencePage_EnableLogging; public static String BuildLogPreferencePage_LogLocation; + public static String GlobalBuildLogPreferencePage_EnableLogging; + public static String GlobalBuildLogPreferencePage_LogLocation; public static String CEditorPreferencePage_folding_title; public static String FoldingConfigurationBlock_enable; public static String FoldingConfigurationBlock_combo_caption; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties index 0b59041e841..fbaed112e24 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties @@ -171,6 +171,10 @@ BuildLogPreferencePage_ChooseLogFile=Choose Log File BuildLogPreferencePage_EnableLogging=Enable build &logging BuildLogPreferencePage_LogLocation=Log &file location: +#Global build logging +GlobalBuildLogPreferencePage_EnableLogging=Enable global build &logging +GlobalBuildLogPreferencePage_LogLocation=Log &file location: + #Folding CEditorPreferencePage_folding_title= &Folding diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/IBuildConsoleManager.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/IBuildConsoleManager.java index cab9de96699..5b0f6240aff 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/IBuildConsoleManager.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/IBuildConsoleManager.java @@ -7,6 +7,7 @@ * * Contributors: * QNX Software Systems - Initial API and implementation + * Alex Collins (Broadcom Corp.) - Global console *******************************************************************************/ package org.eclipse.cdt.ui; @@ -18,9 +19,44 @@ import org.eclipse.jface.text.IDocument; * @noimplement This interface is not intended to be implemented by clients. */ public interface IBuildConsoleManager { + /** + * @return the console to which build output should be printed. + * This may be backed by two console documents: one for the Project + * and one Global + */ IConsole getConsole(IProject project); + /** + * @return the console associated with the specified project + * @since 5.3 + */ + IConsole getProjectConsole(IProject project); + /** + * @return the global console + * @since 5.3 + */ + IConsole getGlobalConsole(); + /** + * @return the document backing the global console + * @since 5.3 + */ + IDocument getGlobalConsoleDocument(); + /** + * @param project + * @return IDocument backing the console for the given project + */ IDocument getConsoleDocument(IProject project); IProject getLastBuiltProject(); void addConsoleListener(IBuildConsoleListener listener); void removeConsoleListener(IBuildConsoleListener listener); + + /** + * Setup the the global console at the start of the build + * @since 5.3 + */ + void startGlobalConsole(); + /** + * Tear down the the global console at the start of the build + * @since 5.3 + */ + void stopGlobalConsole(); }