/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
* Copyright (C) 2011-2012 Eugene Fradkin (eugene.fradkin@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.ui.controls;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.MultiPageEditorSite;
import org.eclipse.ui.progress.UIJob;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.core.CoreMessages;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.ProxyProgressMonitor;
import org.jkiss.dbeaver.model.runtime.load.ILoadVisualizer;
import org.jkiss.dbeaver.ui.*;
import org.jkiss.dbeaver.ui.controls.folders.ITabbedFolderEditorSite;
import org.jkiss.utils.CommonUtils;
import java.util.ArrayList;
/**
* ItemListControl
*/
public class ProgressPageControl extends Composite implements ISearchContextProvider
{
private static final Log log = Log.getLog(ProgressPageControl.class);
private final static int PROGRESS_MIN = 0;
private final static int PROGRESS_MAX = 20;
private boolean showDivider;
private Label listInfoLabel;
private ProgressBar progressBar;
private Text searchText;
private int loadCount = 0;
private ProgressPageControl ownerPageControl = null;
private ProgressPageControl childPageControl = null;
private Composite searchControlsComposite;
private String curInfo;
private String curSearchText;
private volatile Job curSearchJob;
private Color searchNotFoundColor;
private ToolBarManager defaultToolbarManager;
private ToolBarManager searchToolbarManager;
private ToolBarManager customToolbarManager;
private Composite customControlsComposite;
public ProgressPageControl(
Composite parent,
int style)
{
super(parent, style);
GridLayout layout = new GridLayout(1, true);
if ((style & SWT.SHEET) != 0) {
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.verticalSpacing = 0;
layout.horizontalSpacing = 0;
}
//layout.horizontalSpacing = 0;
//layout.verticalSpacing = 0;
this.setLayout(layout);
addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e)
{
disposeControl();
}
});
searchNotFoundColor = new Color(getDisplay(), 255, 128, 128);
}
@Override
public GridLayout getLayout()
{
return (GridLayout)super.getLayout();
}
public void setShowDivider(boolean showDivider)
{
this.showDivider = showDivider;
}
public void setInfo(String info)
{
if (!CommonUtils.isEmpty(info)) {
this.curInfo = info;
}
if (ownerPageControl != null) {
ownerPageControl.setInfo(info);
} else if (listInfoLabel != null && !listInfoLabel.isDisposed()) {
listInfoLabel.setText(info);
}
}
public final Composite createProgressPanel()
{
return createProgressPanel(this);
}
public final void substituteProgressPanel(ProgressPageControl externalPageControl)
{
this.ownerPageControl = externalPageControl;
}
public void createOrSubstituteProgressPanel(IWorkbenchPartSite site) {
ProgressPageControl progressControl = findOwnerPageControl(site);
if (progressControl != null) {
substituteProgressPanel(progressControl);
} else {
createProgressPanel();
}
}
private ProgressPageControl findOwnerPageControl(IWorkbenchPartSite site) {
if (site instanceof ITabbedFolderEditorSite && ((ITabbedFolderEditorSite) site).getFolderEditor() instanceof IProgressControlProvider) {
return ((IProgressControlProvider)((ITabbedFolderEditorSite) site).getFolderEditor()).getProgressControl();
} else if (site instanceof MultiPageEditorSite && ((MultiPageEditorSite) site).getMultiPageEditor() instanceof IProgressControlProvider) {
return ((IProgressControlProvider)((MultiPageEditorSite) site).getMultiPageEditor()).getProgressControl();
} else {
return null;
}
}
private void setChildControl(ProgressPageControl progressPageControl)
{
if (progressPageControl == this.childPageControl) {
return;
}
// if (this.childPageControl != null && progressPageControl != null) {
// log.warn("Overwrite of child page control '" + this.childPageControl); //$NON-NLS-1$
// }
this.childPageControl = progressPageControl;
if (getProgressControl().progressBar == null) {
hideControls(true);
}
}
ProgressPageControl getProgressControl()
{
return ownerPageControl != null ? ownerPageControl : this;
}
public Composite createContentContainer()
{
Composite container = new Composite(this, (getStyle() & SWT.SHEET) == SWT.SHEET ? SWT.NONE : SWT.BORDER);
container.setLayout(new FillLayout());
GridData gd = new GridData(GridData.FILL_BOTH);
gd.horizontalIndent = 0;
gd.verticalIndent = 0;
container.setLayoutData(gd);
return container;
}
public Composite createProgressPanel(Composite container)
{
if (this.ownerPageControl != null) {
throw new IllegalStateException("Can't create page control while substitution control already set"); //$NON-NLS-1$
}
if (showDivider) {
Label separator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL);
separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
}
Composite infoGroup = new Composite(container, SWT.NONE);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
infoGroup.setLayoutData(gd);
GridLayout gl = new GridLayout(2, false);
gl.marginHeight = 0;
gl.marginWidth = 0;
infoGroup.setLayout(gl);
listInfoLabel = new Label(infoGroup, SWT.NONE);
//listInfoLabel.setCursor(infoGroup.getDisplay().getSystemCursor(SWT.CURSOR_HELP));
//listInfoLabel.setBackground(container.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalIndent = 5;
gd.minimumWidth = 100;
listInfoLabel.setLayoutData(gd);
Composite controlsComposite = UIUtils.createPlaceholder(infoGroup, 2, 5);
controlsComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
searchControlsComposite = UIUtils.createPlaceholder(controlsComposite, 1);
//gd.heightHint = listInfoLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT, false).y + gl.verticalSpacing;
searchControlsComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// Placeholder toolbar (need to set initial height of search composite)
new ToolBar(searchControlsComposite, SWT.NONE);
customControlsComposite = new Composite(controlsComposite, SWT.NONE);
gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
//gd.verticalIndent = 3;
customControlsComposite.setLayoutData(gd);
gl = new GridLayout(2, false);
gl.marginHeight = 0;
gl.marginWidth = 0;
customControlsComposite.setLayout(gl);
defaultToolbarManager = new ToolBarManager(SWT.FLAT | SWT.HORIZONTAL | SWT.RIGHT);
customToolbarManager = new ToolBarManager(SWT.FLAT | SWT.HORIZONTAL | SWT.RIGHT);
hideControls(true);
return customControlsComposite;
}
protected void fillCustomActions(IContributionManager contributionManager)
{
if (childPageControl != null) {
childPageControl.fillCustomActions(contributionManager);
}
}
protected void updateActions() {
UIUtils.updateContributionItems(defaultToolbarManager);
UIUtils.updateContributionItems(customToolbarManager);
}
private void hideControls(boolean showDefaultControls)
{
if (searchControlsComposite == null || searchControlsComposite.isDisposed()) {
return;
}
searchControlsComposite.getParent().setRedraw(false);
try {
// Delete all controls created in searchControlsComposite
for (Control child : searchControlsComposite.getChildren()) {
child.dispose();
}
// Nullify all controls
progressBar = null;
searchText = null;
// Create default controls toolbar
if (showDefaultControls) {
((GridLayout)searchControlsComposite.getLayout()).numColumns = 2;
defaultToolbarManager.removeAll();
if (isSearchPossible() && isSearchEnabled()) {
defaultToolbarManager.add(ActionUtils.makeCommandContribution(
PlatformUI.getWorkbench(),
IWorkbenchCommandConstants.EDIT_FIND_AND_REPLACE,
CoreMessages.controls_progress_page_toolbar_title,
UIIcon.SEARCH));
}
Label phLabel = new Label(searchControlsComposite, SWT.NONE);
phLabel.setText(""); //$NON-NLS-1$
phLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
ToolBar defaultToolbar = defaultToolbarManager.createControl(searchControlsComposite);
defaultToolbar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.HORIZONTAL_ALIGN_END));
// Recreate custom controls
for (Control child : customControlsComposite.getChildren()) {
child.dispose();
}
customToolbarManager.removeAll();
fillCustomActions(customToolbarManager);
if (!customToolbarManager.isEmpty()) {
ToolBar toolbar = customToolbarManager.createControl(customControlsComposite);
toolbar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.HORIZONTAL_ALIGN_END));
}
}
searchControlsComposite.getParent().layout();
//customControlsComposite.layout();
} finally {
searchControlsComposite.getParent().setRedraw(true);
}
}
private void createProgressControls()
{
if (progressBar != null || customControlsComposite == null) {
return;
}
hideControls(false);
((GridLayout)searchControlsComposite.getLayout()).numColumns = 2;
progressBar = new ProgressBar(searchControlsComposite, SWT.SMOOTH | SWT.HORIZONTAL);
progressBar.setSize(300, 16);
progressBar.setState(SWT.NORMAL);
progressBar.setMinimum(PROGRESS_MIN);
progressBar.setMaximum(PROGRESS_MAX);
progressBar.setToolTipText(CoreMessages.controls_progress_page_progress_bar_loading_tooltip);
progressBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
ToolBar progressTools = new ToolBar(searchControlsComposite, SWT.HORIZONTAL);
final ToolItem stopButton = new ToolItem(progressTools, SWT.PUSH);
stopButton.setImage(UIUtils.getShardImage(ISharedImages.IMG_ELCL_STOP));
stopButton.setToolTipText(CoreMessages.controls_progress_page_progress_bar_cancel_tooltip);
stopButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e)
{
// Cancel current job
if (cancelProgress()) {
if (!stopButton.isDisposed()) {
stopButton.setEnabled(false);
stopButton.setImage(UIUtils.getShardImage(ISharedImages.IMG_ELCL_STOP_DISABLED));
}
}
}
});
searchControlsComposite.getParent().layout();
}
private void createSearchControls()
{
if (searchText != null) {
return;
}
hideControls(false);
((GridLayout)searchControlsComposite.getLayout()).numColumns = 2;
searchText = new Text(searchControlsComposite, SWT.BORDER);
UIUtils.addFocusTracker(DBeaverUI.getActiveWorkbenchWindow(), UIUtils.INLINE_WIDGET_EDITOR_ID, this.searchText);
if (curSearchText != null) {
searchText.setText(curSearchText);
searchText.setSelection(curSearchText.length());
}
//searchText.setBackground(searchNotFoundColor);
searchText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
searchText.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
switch (e.keyCode) {
case SWT.ESC:
cancelSearch(true);
break;
case SWT.CR:
case SWT.ARROW_UP:
case SWT.ARROW_DOWN:
if (childPageControl != null) {
childPageControl.setFocus();
}
e.doit = false;
//performSearch(SearchType.NEXT);
break;
}
}
});
searchText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e)
{
curSearchText = searchText.getText();
if (curSearchJob == null) {
curSearchJob = new UIJob(CoreMessages.controls_progress_page_job_search) {
@Override
public IStatus runInUIThread(IProgressMonitor monitor)
{
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
performSearch(SearchType.NEXT);
curSearchJob = null;
return Status.OK_STATUS;
}
};
curSearchJob.schedule(200);
}
}
});
//ToolBar searchTools = new ToolBar(searchControlsComposite, SWT.HORIZONTAL);
if (searchToolbarManager == null) {
searchToolbarManager = new ToolBarManager(SWT.FLAT | SWT.HORIZONTAL);
// Do not add prev/next buttons - they doesn't make sense now.
// Keep code just in case
/*
searchToolbarManager.add(ActionUtils.makeCommandContribution(
PlatformUI.getWorkbench(),
IWorkbenchActionDefinitionIds.FIND_NEXT,
null,
UIIcon.ARROW_DOWN));
searchToolbarManager.add(ActionUtils.makeCommandContribution(
PlatformUI.getWorkbench(),
IWorkbenchActionDefinitionIds.FIND_PREVIOUS,
null,
UIIcon.ARROW_UP));
*/
searchToolbarManager.add(new Action(CoreMessages.controls_progress_page_action_close, UIUtils.getShardImageDescriptor(ISharedImages.IMG_ELCL_REMOVE)) {
@Override
public void run()
{
cancelSearch(true);
}
});
}
searchToolbarManager.createControl(searchControlsComposite);
searchControlsComposite.getParent().layout();
}
public void disposeControl()
{
if (searchToolbarManager != null) {
searchToolbarManager.dispose();
searchToolbarManager = null;
}
if (defaultToolbarManager != null) {
defaultToolbarManager.dispose();
defaultToolbarManager = null;
}
if (customToolbarManager != null) {
customToolbarManager.dispose();
customToolbarManager = null;
}
UIUtils.dispose(searchNotFoundColor);
}
protected boolean cancelProgress()
{
return false;
}
protected ISearchExecutor getSearchRunner()
{
if (childPageControl != null) {
return childPageControl.getSearchRunner();
}
return null;
}
@Override
public boolean isSearchPossible()
{
return getSearchRunner() != null;
}
@Override
public boolean isSearchEnabled()
{
return getProgressControl().progressBar == null;
}
@Override
public boolean performSearch(SearchType searchType)
{
getProgressControl().createSearchControls();
if (searchType == SearchType.NONE) {
getProgressControl().searchText.setFocus();
}
if (!CommonUtils.isEmpty(getProgressControl().curSearchText)) {
int options = 0;
if (searchType == SearchType.PREVIOUS) {
options |= ISearchExecutor.SEARCH_PREVIOUS;
} else {
options |= ISearchExecutor.SEARCH_NEXT;
}
boolean success = getSearchRunner().performSearch(getProgressControl().curSearchText, options);
getProgressControl().searchText.setBackground(success ? null : searchNotFoundColor);
return success;
} else {
cancelSearch(false);
return true;
}
}
private void cancelSearch(boolean hide)
{
if (curSearchJob != null) {
curSearchJob.cancel();
curSearchJob = null;
}
getSearchRunner().cancelSearch();
if (hide) {
hideControls(true);
} else {
getProgressControl().searchText.setBackground(null);
}
}
public void activate(boolean active)
{
if (active && curInfo != null) {
setInfo(curInfo);
}
if (this.ownerPageControl != null) {
if (active) {
this.ownerPageControl.setChildControl(this);
} else {
// Do NOT set child to NULL because deactivation usually means just focus lost
// and we don't want to deactivate page control on focus loss.
//this.ownerPageControl.setChildControl(null);
}
}
}
/*
public void run(boolean fork, boolean cancelable, final IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException
{
Job job = new Job("Progress") {
@Override
protected IStatus run(IProgressMonitor monitor)
{
try {
runnable.run(monitor);
} catch (InvocationTargetException e) {
return RuntimeUtils.makeExceptionStatus(e.getTargetException());
} catch (InterruptedException e) {
// do nothing
}
return Status.OK_STATUS;
}
};
job.schedule();
job.join();
}
*/
private static class TaskInfo {
final String name;
final int totalWork;
int progress;
private TaskInfo(String name, int totalWork)
{
this.name = name;
this.totalWork = totalWork;
}
}
public class ProgressVisualizer<RESULT> implements ILoadVisualizer<RESULT> {
private boolean completed = false;
private String curStatus;
private final java.util.List<TaskInfo> tasksRunning = new ArrayList<>();
@Override
public DBRProgressMonitor overwriteMonitor(final DBRProgressMonitor monitor)
{
return new ProxyProgressMonitor(monitor) {
@Override
public void beginTask(final String name, int totalWork)
{
super.beginTask(name, totalWork);
curStatus = name;
synchronized (tasksRunning) {
tasksRunning.add(new TaskInfo(name, totalWork));
}
}
@Override
public void done()
{
super.done();
curStatus = ""; //$NON-NLS-1$
synchronized (tasksRunning) {
if (tasksRunning.isEmpty()) {
log.warn("Task end when no tasks are running"); //$NON-NLS-1$
} else {
tasksRunning.remove(tasksRunning.size() - 1);
}
}
}
@Override
public void subTask(String name)
{
super.subTask(name);
curStatus = name;
}
@Override
public void worked(int work)
{
super.worked(work);
synchronized (tasksRunning) {
if (!tasksRunning.isEmpty()) {
tasksRunning.get(tasksRunning.size() - 1).progress += work;
}
}
}
};
}
private TaskInfo getCurTaskInfo()
{
for (int i = tasksRunning.size() - 1; i >= 0; i--) {
if (tasksRunning.get(i).totalWork > 1) {
return tasksRunning.get(i);
}
}
return null;
}
@Override
public boolean isCompleted()
{
return completed;
}
@Override
public void visualizeLoading()
{
if (!getProgressControl().isDisposed()) {
getProgressControl().createProgressControls();
synchronized (tasksRunning) {
TaskInfo taskInfo = getCurTaskInfo();
ProgressBar progressBar = getProgressControl().progressBar;
if (progressBar != null) {
if (taskInfo != null) {
progressBar.setMaximum(taskInfo.totalWork);
progressBar.setSelection(taskInfo.progress);
} else {
progressBar.setMaximum(PROGRESS_MAX);
progressBar.setSelection(loadCount);
}
}
}
if (curStatus != null) {
setInfo(curStatus);
}
loadCount++;
if (loadCount > PROGRESS_MAX) {
loadCount = PROGRESS_MIN;
}
}
}
@Override
public void completeLoading(RESULT result)
{
completed = true;
if (ProgressPageControl.this.isDisposed()) {
return;
}
visualizeLoading();
loadCount = 0;
ProgressBar progressBar = getProgressControl().progressBar;
if (progressBar != null && !progressBar.isDisposed()) {
progressBar.setState(SWT.PAUSED);
getProgressControl().hideControls(true);
}
}
}
}