de.walware.statet.nico.ui.util.ExportConsoleOutputWizard.java Source code

Java tutorial

Introduction

Here is the source code for de.walware.statet.nico.ui.util.ExportConsoleOutputWizard.java

Source

/*=============================================================================#
 # Copyright (c) 2009-2015 Stephan Wahlbrink (WalWare.de) 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:
 #     Stephan Wahlbrink - initial API and implementation
 #=============================================================================*/

package de.walware.statet.nico.ui.util;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.atomic.AtomicReference;

import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.wizard.WizardPageSupport;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.text.AbstractDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.ui.console.TextConsoleViewer;
import org.eclipse.ui.statushandlers.StatusManager;

import de.walware.ecommons.databinding.jface.DataBindingSupport;
import de.walware.ecommons.io.FileUtil;
import de.walware.ecommons.ui.util.DialogUtil;
import de.walware.ecommons.ui.util.LayoutUtil;
import de.walware.ecommons.ui.util.UIAccess;

import de.walware.statet.nico.core.runtime.ToolProcess;
import de.walware.statet.nico.core.util.TrackWriter;
import de.walware.statet.nico.core.util.TrackingConfiguration;
import de.walware.statet.nico.internal.ui.NicoUIPlugin;
import de.walware.statet.nico.ui.NicoUI;
import de.walware.statet.nico.ui.console.NIConsoleOutputStream;
import de.walware.statet.nico.ui.console.NIConsolePage;

/**
 * Wizard to export the console output
 */
public class ExportConsoleOutputWizard extends Wizard {

    private static final String FILE_HISTORY_SETTINGSKEY = "FileLocation_history";

    protected static class ConfigurationPage extends WizardPage {

        private final NIConsolePage fConsolePage;

        private final TrackingConfiguration fConfig;
        private final WritableValue fOpenValue;

        private TrackingConfigurationComposite fConfigControl;
        private Button fOpenControl;

        private DataBindingSupport fDataBinding;

        public ConfigurationPage(final NIConsolePage page, final TrackingConfiguration config,
                final boolean selectionMode) {
            super("ConfigureConsoleExportPage"); //$NON-NLS-1$
            fConsolePage = page;
            setTitle(selectionMode ? "Export Selected Output" : "Export Current Output");
            setDescription("Select the content to export and the destination file");

            fConfig = config;
            fOpenValue = new WritableValue(false, Boolean.class);
        }

        @Override
        public void createControl(final Composite parent) {
            initializeDialogUnits(parent);

            final Composite composite = new Composite(parent, SWT.NONE);
            composite.setLayout(LayoutUtil.createContentGrid(1));

            fConfigControl = createTrackingControl(composite);
            fConfigControl.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

            fConfigControl.getPathInput().getValidator().setOnLateResolve(IStatus.ERROR);
            fConfigControl.getPathInput().setShowInsertVariable(true, DialogUtil.DEFAULT_NON_ITERACTIVE_FILTERS,
                    fConsolePage.getTool().getWorkspaceData().getStringVariables());
            fConfigControl.setInput(fConfig);

            final Composite additionalOptions = createAdditionalOptions(composite);
            additionalOptions.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

            LayoutUtil.addSmallFiller(composite, true);
            final ToolInfoGroup info = new ToolInfoGroup(composite, fConsolePage.getTool());
            info.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

            Dialog.applyDialogFont(composite);
            setControl(composite);

            fConfigControl.getPathInput().setHistory(getDialogSettings().getArray(FILE_HISTORY_SETTINGSKEY));
            final Realm realm = Realm.getDefault();
            fDataBinding = new DataBindingSupport(composite);
            addBindings(fDataBinding);
            WizardPageSupport.create(this, fDataBinding.getContext());
        }

        protected TrackingConfigurationComposite createTrackingControl(final Composite parent) {
            return new TrackingConfigurationComposite(parent) {
                @Override
                protected boolean enableFullMode() {
                    return false;
                }

                @Override
                protected boolean enableFilePathAsCombo() {
                    return true;
                }
            };
        }

        protected Composite createAdditionalOptions(final Composite parent) {
            final Group composite = new Group(parent, SWT.NONE);
            composite.setText("Actions:");
            composite.setLayout(LayoutUtil.applyGroupDefaults(new GridLayout(), 1));

            fOpenControl = new Button(composite, SWT.CHECK);
            fOpenControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
            fOpenControl.setText("Open in &Editor");

            return composite;
        }

        protected void addBindings(final DataBindingSupport db) {
            fConfigControl.addBindings(db);

            db.getContext().bindValue(SWTObservables.observeSelection(fOpenControl), fOpenValue);
        }

        public boolean getOpenInEditor() {
            return ((Boolean) fOpenValue.getValue()).booleanValue();
        }

        protected void saveSettings() {
            final IDialogSettings settings = getDialogSettings();
            DialogUtil.saveHistorySettings(settings, FILE_HISTORY_SETTINGSKEY, fConfig.getFilePath());
        }

    }

    private TrackingConfiguration fConfig;
    private final int fSelectionLength;

    private final NIConsolePage fConsolePage;

    private ConfigurationPage fConfigPage;

    public ExportConsoleOutputWizard(final NIConsolePage consolePage) {
        fConsolePage = consolePage;
        fSelectionLength = ((ITextSelection) consolePage.getOutputViewer().getSelection()).getLength();

        setWindowTitle("Export Console Output");
        setNeedsProgressMonitor(true);

        setDialogSettings(
                DialogUtil.getDialogSettings(NicoUIPlugin.getDefault(), "tools/ExportConsoleOutputWizard"));
    }

    protected TrackingConfiguration createTrackingConfiguration() {
        return new TrackingConfiguration(""); //$NON-NLS-1$
    }

    @Override
    public void addPages() {
        fConfig = createTrackingConfiguration();
        fConfigPage = new ConfigurationPage(fConsolePage, fConfig, fSelectionLength > 0);
        addPage(fConfigPage);
    }

    @Override
    public boolean performFinish() {
        fConfigPage.saveSettings();
        final boolean openInEditor = fConfigPage.getOpenInEditor();
        try {
            getContainer().run(true, true, new IRunnableWithProgress() {
                @Override
                public void run(final IProgressMonitor monitor)
                        throws InvocationTargetException, InterruptedException {
                    final SubMonitor progress = SubMonitor.convert(monitor, "Export Output", 100);
                    final TextConsoleViewer outputViewer = fConsolePage.getOutputViewer();
                    final AbstractDocument document = (AbstractDocument) outputViewer.getDocument();

                    final IJobManager jobManager = Job.getJobManager();
                    final ISchedulingRule schedulingRule = fConsolePage.getConsole().getSchedulingRule();
                    jobManager.beginRule(schedulingRule, progress.newChild(1));
                    try {
                        if (fSelectionLength > 0) {
                            final AtomicReference<ITextSelection> currentSelection = new AtomicReference<ITextSelection>();
                            getShell().getDisplay().syncExec(new Runnable() {
                                @Override
                                public void run() {
                                    final ITextSelection selection = (ITextSelection) outputViewer.getSelection();
                                    if (selection.getLength() != fSelectionLength) {
                                        final boolean continueExport = MessageDialog.openQuestion(getShell(),
                                                "Export Output",
                                                "The selection is changed due to updates in the console. Do you want to continue nevertheless?");
                                        if (!continueExport) {
                                            return;
                                        }
                                    }
                                    currentSelection.set(selection);
                                }
                            });
                            final ITextSelection selection = currentSelection.get();
                            if (selection == null) {
                                return;
                            }

                            progress.setWorkRemaining(95);
                            export(document, selection.getOffset(), selection.getLength(), openInEditor, progress);
                        } else {
                            progress.setWorkRemaining(95);
                            export(document, 0, document.getLength(), openInEditor, progress);
                        }
                    } finally {
                        jobManager.endRule(schedulingRule);
                    }
                }
            });
        } catch (final InvocationTargetException e) {
            final Throwable cause = e.getCause();
            StatusManager.getManager()
                    .handle(new Status(IStatus.ERROR, NicoUI.PLUGIN_ID, -1,
                            "An error occurred when exporting console output to file.", cause),
                            StatusManager.LOG | StatusManager.SHOW);
            return !(cause instanceof CoreException || cause instanceof IOException);
        } catch (final InterruptedException e) {
        }
        return true;
    }

    private void export(final AbstractDocument document, final int offset, final int length,
            final boolean openInEditor, final SubMonitor progress) throws InvocationTargetException {
        OutputStream outputStream = null;
        Writer outputWriter = null;
        try {
            String filePath = fConfig.getFilePath();
            filePath = TrackWriter.resolveVariables(filePath, fConsolePage.getTool().getWorkspaceData());
            final IFileStore fileStore = FileUtil.getFileStore(filePath);

            outputStream = fileStore.openOutputStream(fConfig.getFileMode(), progress.newChild(1));
            if (fileStore.fetchInfo().getLength() <= 0L) {
                FileUtil.prepareTextOutput(outputStream, fConfig.getFileEncoding());
            }
            outputWriter = new BufferedWriter(new OutputStreamWriter(outputStream, fConfig.getFileEncoding()));

            if (fConfig.getPrependTimestamp()) {
                final ToolProcess process = fConsolePage.getConsole().getProcess();
                outputWriter.append(process.createTimestampComment(process.getConnectionTimestamp()));
            }

            if (fConfig.getTrackStreamInfo() && fConfig.getTrackStreamInput() && fConfig.getTrackStreamOutput()
                    && !fConfig.getTrackStreamOutputTruncate()) {
                int pOffset = offset;
                int pLength = length;
                while (pLength > 0) {
                    final int currentLength = Math.min(pLength, 32768);
                    outputWriter.append(document.get(pOffset, currentLength));
                    pOffset += currentLength;
                    pLength -= currentLength;
                }
            } else {
                final ITypedRegion[] partitions = document.getDocumentPartitioner().computePartitioning(offset,
                        length);
                final SubMonitor exportProgress = progress.newChild(90);
                int counter = partitions.length;
                for (final ITypedRegion partition : partitions) {
                    exportProgress.setWorkRemaining(counter--);
                    final String type = partition.getType();
                    String text2 = null;

                    if (type == null) {
                        continue;
                    }

                    int pOffset;
                    int pLength;
                    if (type.equals(NIConsoleOutputStream.INFO_STREAM_ID)) {
                        if (!fConfig.getTrackStreamInfo()) {
                            continue;
                        }
                        pOffset = Math.max(offset, partition.getOffset());
                        pLength = Math.min(offset + length, partition.getOffset() + partition.getLength())
                                - pOffset;
                    } else if (type.equals(NIConsoleOutputStream.INPUT_STREAM_ID)) {
                        if (!fConfig.getTrackStreamInput()) {
                            continue;
                        }
                        pOffset = Math.max(offset, partition.getOffset());
                        pLength = Math.min(offset + length, partition.getOffset() + partition.getLength())
                                - pOffset;
                    } else if (type.equals(NIConsoleOutputStream.OUTPUT_STREAM_ID)) {
                        if (!fConfig.getTrackStreamOutput()) {
                            continue;
                        }
                        pOffset = Math.max(offset, partition.getOffset());
                        pLength = Math.min(offset + length, partition.getOffset() + partition.getLength())
                                - pOffset;
                        if (fConfig.getTrackStreamOutputTruncate()) {
                            final int firstLine = document.getLineOfOffset(pOffset);
                            final int lastLine = document.getLineOfOffset(pOffset + pLength);
                            if (lastLine - firstLine + 1 > fConfig.getTrackStreamOutputTruncateLines()) {
                                pLength = document.getLineOffset(
                                        firstLine + fConfig.getTrackStreamOutputTruncateLines()) - pOffset;
                                text2 = "[...] (truncated)\n\n";
                            }
                        }
                    } else if (type.equals(NIConsoleOutputStream.ERROR_STREAM_ID)) {
                        if (!fConfig.getTrackStreamOutput()) {
                            continue;
                        }
                        pOffset = Math.max(offset, partition.getOffset());
                        pLength = Math.min(offset + length, partition.getOffset() + partition.getLength())
                                - pOffset;
                    } else {
                        pOffset = Math.max(offset, partition.getOffset());
                        pLength = Math.min(offset + length, partition.getOffset() + partition.getLength())
                                - pOffset;
                    }

                    while (pLength > 0) {
                        final int currentLength = Math.min(pLength, 32768);
                        outputWriter.append(document.get(pOffset, currentLength));
                        pOffset += currentLength;
                        pLength -= currentLength;
                    }
                    if (text2 != null) {
                        outputWriter.append(text2);
                    }
                }
            }

            outputWriter.close();
            outputWriter = null;

            if (openInEditor) {
                UIAccess.getDisplay().asyncExec(new Runnable() {
                    @Override
                    public void run() {
                        OpenTrackingFilesContributionItem.open("export", fileStore);
                    }
                });
            }
        } catch (final Exception e) {
            throw new InvocationTargetException(e);
        } finally {
            if (outputWriter != null) {
                try {
                    outputWriter.close();
                } catch (final IOException ignore) {
                }
            } else if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (final IOException ignore) {
                }
            }
        }
    }

}