/*******************************************************************************
* Copyright (c) 2015 Tasktop Technologies.
* 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:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.tasks.ui.migrator;
import static com.google.common.collect.Iterables.any;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.eclipse.mylyn.internal.tasks.ui.migrator.TaskPredicates.isQueryForConnector;
import static org.eclipse.mylyn.internal.tasks.ui.migrator.TaskPredicates.isSynchronizing;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
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.dialogs.IMessageProvider;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.mylyn.internal.tasks.core.RepositoryQuery;
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal;
import org.eclipse.mylyn.internal.tasks.ui.views.TaskRepositoryLabelProvider;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.AbstractRepositoryConnectorUi;
import org.eclipse.mylyn.tasks.ui.TaskElementLabelProvider;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
public class CompleteConnectorMigrationWizard extends Wizard {
final class MapContentProvider implements ITreeContentProvider {
private final Map<?, ? extends Collection<?>> map;
private MapContentProvider(Map<?, ? extends Collection<?>> map) {
this.map = map;
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
@Override
public void dispose() {
}
@Override
public boolean hasChildren(Object element) {
return map.containsKey(element);
}
@Override
public Object getParent(Object element) {
return null;
}
@Override
public Object[] getElements(Object inputElement) {
if (inputElement instanceof Map) {
return ((Map<?, ?>) inputElement).keySet().toArray();
}
return null;
}
@Override
public Object[] getChildren(Object parentElement) {
if (map.get(parentElement) == null) {
return null;
}
return map.get(parentElement).toArray();
}
}
private final ConnectorMigrator migrator;
public CompleteConnectorMigrationWizard(ConnectorMigrator migrator) {
this.migrator = migrator;
}
@Override
public void addPages() {
setWindowTitle(Messages.CompleteConnectorMigrationWizard_Complete_Connector_Migration);
if (!migrator.allQueriesMigrated()) {
addPage(new WizardPage(Messages.CompleteConnectorMigrationWizard_Migrate_Queries) {
@Override
public void createControl(Composite parent) {
setTitle(Messages.CompleteConnectorMigrationWizard_Have_You_Recreated_Your_Queries);
String message = Messages.CompleteConnectorMigrationWizard_ensure_created_queries;
if (migrator.anyQueriesMigrated()) {
message = Messages.CompleteConnectorMigrationWizard_Queries_not_migrated;
}
setMessage(NLS.bind(Messages.CompleteConnectorMigrationWizard_first_page_message, message),
IMessageProvider.INFORMATION);
Composite c = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(true).applyTo(c);
Label oldQueriesLabel = new Label(c, SWT.NONE);
oldQueriesLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT));
oldQueriesLabel.setText(Messages.CompleteConnectorMigrationWizard_Queries_Using_Old_Connectors);
Label newQueriesLabel = new Label(c, SWT.NONE);
newQueriesLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT));
newQueriesLabel.setText(Messages.CompleteConnectorMigrationWizard_Queries_Using_New_Connectors);
createQueryTree(c, createRepositoryQueryMap(migrator.getSelectedConnectors().keySet()));
createQueryTree(c, createRepositoryQueryMap(migrator.getSelectedConnectors().values()));
setControl(c);
}
});
}
addPage(new WizardPage(Messages.CompleteConnectorMigrationWizard_Complete_Migration) {
@Override
public void createControl(Composite parent) {
setTitle(Messages.CompleteConnectorMigrationWizard_Complete_Migration);
setMessage(Messages.CompleteConnectorMigrationWizard_second_page_message, IMessageProvider.INFORMATION);
Composite c = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().applyTo(c);
Text text = new Text(c, SWT.READ_ONLY | SWT.MULTI | SWT.WRAP);
text.setText(Messages.CompleteConnectorMigrationWizard_second_page_text);
GridDataFactory.fillDefaults()
.align(SWT.FILL, SWT.FILL)
.grab(true, true)
.hint(600, SWT.DEFAULT)
.applyTo(text);
setControl(c);
}
@Override
public boolean isPageComplete() {
return super.isPageComplete() && isCurrentPage();
}
});
}
protected TreeViewer createQueryTree(Composite parent,
final Map<TaskRepository, ? extends Set<RepositoryQuery>> queries) {
final TreeViewer viewer = new TreeViewer(parent);
GridDataFactory.fillDefaults().grab(false, true).hint(500, SWT.DEFAULT).applyTo(viewer.getControl());
viewer.setContentProvider(new MapContentProvider(queries));
viewer.setInput(queries);
viewer.setSorter(new ViewerSorter());
viewer.setLabelProvider(new TaskElementLabelProvider() {
private final TaskRepositoryLabelProvider repositoryLabelProvider = new TaskRepositoryLabelProvider();
@Override
public Image getImage(Object element) {
if (element instanceof TaskRepository) {
return repositoryLabelProvider.getImage(element);
}
return super.getImage(element);
}
@Override
public String getText(Object object) {
if (object instanceof TaskRepository) {
return repositoryLabelProvider.getText(object);
}
return super.getText(object);
}
});
viewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
if (viewer.getSelection() instanceof IStructuredSelection) {
Object element = ((IStructuredSelection) viewer.getSelection()).getFirstElement();
if (element instanceof IRepositoryQuery) {
IRepositoryQuery query = (IRepositoryQuery) element;
AbstractRepositoryConnectorUi connectorUi = TasksUiPlugin
.getConnectorUi(query.getConnectorKind());
TasksUiInternal.openEditQueryDialog(connectorUi, query);
}
}
}
});
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
viewer.expandAll();
}
});
return viewer;
}
@Override
public boolean performFinish() {
Job job = new Job(Messages.CompleteConnectorMigrationWizard_Migrating_Tasks_and_Private_Data) {
@Override
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask(Messages.CompleteConnectorMigrationWizard_Completing_connector_migration,
IProgressMonitor.UNKNOWN);
Collection<String> newConnectors = migrator.getSelectedConnectors().values();
waitForQueriesToSynchronize(newConnectors, monitor);
migrator.migrateTasks(monitor);
return Status.OK_STATUS;
}
};
job.setUser(true);
job.setSystem(false);
job.schedule();
return true;
}
protected void waitForQueriesToSynchronize(Collection<String> newConnectors, IProgressMonitor monitor) {
monitor.subTask(Messages.CompleteConnectorMigrationWizard_Waiting_for_queries_to_synchronize);
Iterable<RepositoryQuery> queries = Iterables.concat(createRepositoryQueryMap(newConnectors).values());
long start = System.currentTimeMillis();
while (any(queries, isSynchronizing())
&& System.currentTimeMillis() - start < MILLISECONDS.convert(20, MINUTES)) {
try {
Thread.sleep(MILLISECONDS.convert(3, SECONDS));
} catch (InterruptedException e) {// NOSONAR
}
}
}
protected Map<TaskRepository, Set<RepositoryQuery>> createRepositoryQueryMap(Collection<String> kinds) {
Builder<TaskRepository, Set<RepositoryQuery>> repositories = ImmutableMap.builder();
for (final String kind : kinds) {
for (TaskRepository repository : migrator.getRepositoryManager().getRepositories(kind)) {
Set<RepositoryQuery> queriesForUrl = TasksUiPlugin.getTaskList()
.getRepositoryQueries(repository.getRepositoryUrl());
Set<RepositoryQuery> queries = Sets.filter(queriesForUrl, isQueryForConnector(kind));
if (!queries.isEmpty()) {
repositories.put(repository, queries);
}
}
}
return repositories.build();
}
}