| /******************************************************************************* |
| * Copyright (c) 2007, 2018 IBM 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: |
| * IBM Corporation - initial API and implementation |
| * Ericsson AB (Pascal Rapicault) - bug 398539 |
| *******************************************************************************/ |
| package org.eclipse.equinox.p2.ui; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; |
| import org.eclipse.equinox.internal.p2.ui.*; |
| import org.eclipse.equinox.internal.p2.ui.dialogs.*; |
| import org.eclipse.equinox.internal.p2.ui.model.*; |
| import org.eclipse.equinox.internal.p2.ui.viewers.*; |
| import org.eclipse.equinox.internal.provisional.p2.repository.RepositoryEvent; |
| import org.eclipse.equinox.p2.core.ProvisionException; |
| import org.eclipse.equinox.p2.operations.ProvisioningSession; |
| import org.eclipse.equinox.p2.operations.RepositoryTracker; |
| import org.eclipse.jface.dialogs.*; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.layout.*; |
| import org.eclipse.jface.preference.PreferencePage; |
| import org.eclipse.jface.viewers.*; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.accessibility.AccessibleListener; |
| import org.eclipse.swt.custom.BusyIndicator; |
| import org.eclipse.swt.dnd.*; |
| import org.eclipse.swt.events.*; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.*; |
| import org.eclipse.ui.*; |
| import org.eclipse.ui.dialogs.PatternFilter; |
| import org.eclipse.ui.progress.WorkbenchJob; |
| import org.eclipse.ui.statushandlers.StatusManager; |
| |
| /** |
| * Page that allows users to update, add, remove, import, and |
| * export repositories. This page can be hosted inside a preference |
| * dialog or inside its own dialog. |
| * |
| * When hosting this page inside a non-preference dialog, some of the |
| * dialog methods will likely have to call page methods. The following |
| * snippet shows how to host this page inside a TitleAreaDialog. |
| * <pre> |
| * TitleAreaDialog dialog = new TitleAreaDialog(shell) { |
| * |
| * RepositoryManipulationPage page; |
| * |
| * protected Control createDialogArea(Composite parent) { |
| * page = new RepositoryManipulationPage(); |
| * page.setProvisioningUI(ProvisioningUI.getDefaultUI()); |
| * page.createControl(parent); |
| * this.setTitle("Software Sites"); |
| * this.setMessage("The enabled sites will be searched for software. Disabled sites are ignored."); |
| * return page.getControl(); |
| * } |
| * |
| * protected void okPressed() { |
| * if (page.performOk()) |
| * super.okPressed(); |
| * } |
| * |
| * protected void cancelPressed() { |
| * if (page.performCancel()) |
| * super.cancelPressed(); |
| * } |
| * }; |
| * dialog.open(); |
| * </pre> |
| * |
| * @noextend This class is not intended to be subclassed by clients. |
| * |
| * @since 2.0 |
| */ |
| public class RepositoryManipulationPage extends PreferencePage implements IWorkbenchPreferencePage, ICopyable { |
| final static String DEFAULT_FILTER_TEXT = ProvUIMessages.RepositoryManipulationPage_DefaultFilterString; |
| private final static int FILTER_DELAY = 200; |
| |
| StructuredViewerProvisioningListener listener; |
| CheckboxTableViewer repositoryViewer; |
| Table table; |
| ProvisioningUI ui; |
| Policy policy; |
| Display display; |
| boolean changed = false; |
| MetadataRepositoryElementComparator comparator; |
| RepositoryDetailsLabelProvider labelProvider; |
| RepositoryTracker tracker; |
| RepositoryTracker localCacheRepoManipulator; |
| /** |
| * The input field is initialized lazily and should only be accessed via the {@link #getInput()} method. |
| */ |
| CachedMetadataRepositories input; |
| Text pattern, details; |
| PatternFilter filter; |
| WorkbenchJob filterJob; |
| Button addButton, removeButton, editButton, refreshButton, disableButton, exportButton; |
| |
| private Map<MetadataRepositoryElement, URI> originalURICache = new HashMap<>(2); |
| private Map<MetadataRepositoryElement, String> originalNameCache = new HashMap<>(2); |
| |
| class CachedMetadataRepositories extends MetadataRepositories { |
| private Hashtable<String, MetadataRepositoryElement> cachedElements; |
| |
| CachedMetadataRepositories() { |
| super(ui); |
| setIncludeDisabledRepositories(getPolicy().getRepositoriesVisible()); |
| } |
| |
| @Override |
| public int getQueryType() { |
| return QueryProvider.METADATA_REPOS; |
| } |
| |
| @Override |
| public Object[] fetchChildren(Object o, IProgressMonitor monitor) { |
| if (cachedElements == null) { |
| Object[] children = super.fetchChildren(o, monitor); |
| cachedElements = new Hashtable<>(children.length); |
| for (int i = 0; i < children.length; i++) { |
| if (children[i] instanceof MetadataRepositoryElement) { |
| put((MetadataRepositoryElement) children[i]); |
| } |
| } |
| } |
| return cachedElements.values().toArray(); |
| } |
| |
| MetadataRepositoryElement[] getElements() { |
| return cachedElements.values().toArray(new MetadataRepositoryElement[cachedElements.size()]); |
| } |
| |
| void remove(MetadataRepositoryElement element) { |
| cachedElements.remove(getKey(element.getLocation())); |
| } |
| |
| void put(MetadataRepositoryElement element) { |
| cachedElements.put(getKey(element.getLocation()), element); |
| } |
| |
| MetadataRepositoryElement get(URI location) { |
| return cachedElements.get(getKey(location)); |
| } |
| |
| String getKey(URI location) { |
| String key = URIUtil.toUnencodedString(location); |
| int length = key.length(); |
| if (length > 0 && key.charAt(length - 1) == '/') { |
| key = key.substring(0, length - 1); |
| } |
| return key; |
| } |
| |
| } |
| |
| class MetadataRepositoryPatternFilter extends PatternFilter { |
| MetadataRepositoryPatternFilter() { |
| setIncludeLeadingWildcard(true); |
| } |
| |
| @Override |
| public boolean isElementVisible(Viewer viewer, Object element) { |
| if (element instanceof MetadataRepositoryElement) { |
| return wordMatches(labelProvider.getColumnText(element, RepositoryDetailsLabelProvider.COL_NAME) + " " + labelProvider.getColumnText(element, RepositoryDetailsLabelProvider.COL_LOCATION)); //$NON-NLS-1$ |
| } |
| return false; |
| } |
| } |
| |
| /** |
| * Create a repository manipulation page that will display the repositories |
| * available to the user. |
| */ |
| public RepositoryManipulationPage() { |
| this.setProvisioningUI(ProvisioningUI.getDefaultUI()); |
| } |
| |
| /** |
| * Set the provisioning UI that provides the session, policy, and other |
| * services for the UI. This method must be called before the contents are |
| * created or it will have no effect. |
| * |
| * @param ui the provisioning UI to use for this page. |
| */ |
| public void setProvisioningUI(ProvisioningUI ui) { |
| this.ui = ui; |
| this.policy = ui.getPolicy(); |
| tracker = ui.getRepositoryTracker(); |
| } |
| |
| @Override |
| protected Control createContents(Composite parent) { |
| display = parent.getDisplay(); |
| // The help refers to the full-blown dialog. No help if it's read only. |
| if (policy.getRepositoriesVisible()) |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(parent.getShell(), IProvHelpContextIds.REPOSITORY_MANIPULATION_DIALOG); |
| |
| Composite composite = new Composite(parent, SWT.NONE); |
| |
| // Filter box |
| pattern = new Text(composite, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.CANCEL); |
| pattern.getAccessible().addAccessibleListener(AccessibleListener.getNameAdapter(e -> e.result = DEFAULT_FILTER_TEXT)); |
| pattern.setText(DEFAULT_FILTER_TEXT); |
| pattern.selectAll(); |
| pattern.addModifyListener(e -> applyFilter()); |
| |
| pattern.addKeyListener(KeyListener.keyPressedAdapter(e -> { |
| if (e.keyCode == SWT.ARROW_DOWN) { |
| if (table.getItemCount() > 0) { |
| table.setFocus(); |
| } else if (e.character == SWT.CR) { |
| return; |
| } |
| } |
| })); |
| |
| pattern.addFocusListener(FocusListener.focusGainedAdapter(e -> { |
| display.asyncExec(() -> { |
| if (!pattern.isDisposed()) { |
| if (DEFAULT_FILTER_TEXT.equals(pattern.getText().trim())) { |
| pattern.selectAll(); |
| } |
| } |
| }); |
| })); |
| |
| // spacer to fill other column |
| if (policy.getRepositoriesVisible()) |
| new Label(composite, SWT.NONE); |
| |
| // Table of available repositories |
| table = new Table(composite, SWT.CHECK | SWT.MULTI | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); |
| repositoryViewer = new CheckboxTableViewer(table); |
| |
| // Key listener for delete |
| table.addKeyListener(KeyListener.keyPressedAdapter(e -> { |
| if (e.keyCode == SWT.DEL) { |
| removeRepositories(); |
| } |
| })); |
| setTableColumns(); |
| CopyUtils.activateCopy(this, table); |
| |
| repositoryViewer.setComparer(new ProvElementComparer()); |
| comparator = new MetadataRepositoryElementComparator(RepositoryDetailsLabelProvider.COL_NAME); |
| repositoryViewer.setComparator(comparator); |
| filter = new MetadataRepositoryPatternFilter(); |
| repositoryViewer.setFilters(new ViewerFilter[] {filter}); |
| // We don't need a deferred content provider because we are caching local results before |
| // actually querying |
| repositoryViewer.setContentProvider(new ProvElementContentProvider()); |
| labelProvider = new RepositoryDetailsLabelProvider(); |
| repositoryViewer.setLabelProvider(labelProvider); |
| |
| // Edit the nickname |
| repositoryViewer.setCellModifier(new ICellModifier() { |
| @Override |
| public boolean canModify(Object element, String property) { |
| return element instanceof MetadataRepositoryElement; |
| } |
| |
| @Override |
| public Object getValue(Object element, String property) { |
| return ((MetadataRepositoryElement) element).getName(); |
| } |
| |
| @Override |
| public void modify(Object element, String property, Object value) { |
| if (value != null && value.toString().length() >= 0) { |
| MetadataRepositoryElement repo; |
| if (element instanceof Item) { |
| repo = (MetadataRepositoryElement) ((Item) element).getData(); |
| } else if (element instanceof MetadataRepositoryElement) { |
| repo = (MetadataRepositoryElement) element; |
| } else { |
| return; |
| } |
| if (!value.toString().equals(repo.getName())) { |
| changed = true; |
| repo.setNickname(value.toString()); |
| if (comparator.getSortKey() == RepositoryDetailsLabelProvider.COL_NAME) |
| repositoryViewer.refresh(true); |
| else |
| repositoryViewer.update(repo, null); |
| } |
| } |
| } |
| |
| }); |
| repositoryViewer.setColumnProperties(new String[] {"nickname"}); //$NON-NLS-1$ |
| repositoryViewer.setCellEditors(new CellEditor[] {new TextCellEditor(repositoryViewer.getTable())}); |
| |
| repositoryViewer.addSelectionChangedListener(event -> { |
| if (policy.getRepositoriesVisible()) |
| validateButtons(); |
| setDetails(); |
| }); |
| |
| repositoryViewer.setCheckStateProvider(new ICheckStateProvider() { |
| @Override |
| public boolean isChecked(Object element) { |
| return ((MetadataRepositoryElement) element).isEnabled(); |
| } |
| |
| @Override |
| public boolean isGrayed(Object element) { |
| return false; |
| } |
| }); |
| |
| repositoryViewer.addCheckStateListener(event -> { |
| MetadataRepositoryElement element = (MetadataRepositoryElement) event.getElement(); |
| element.setEnabled(event.getChecked()); |
| // paranoid that an equal but not identical element was passed in as the selection. |
| // update the cache map just in case. |
| getInput().put(element); |
| // update the viewer to show the change |
| updateForEnablementChange(new MetadataRepositoryElement[] {element}); |
| }); |
| |
| // Input last |
| repositoryViewer.setInput(getInput()); |
| |
| // Drop targets and vertical buttons only if repository manipulation is provided. |
| if (policy.getRepositoriesVisible()) { |
| DropTarget target = new DropTarget(table, DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK); |
| target.setTransfer(new Transfer[] {URLTransfer.getInstance(), FileTransfer.getInstance()}); |
| target.addDropListener(new RepositoryManipulatorDropTarget(ui, table)); |
| |
| // Vertical buttons |
| Composite verticalButtonBar = createVerticalButtonBar(composite); |
| GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).applyTo(verticalButtonBar); |
| listener = getViewerProvisioningListener(); |
| |
| ProvUI.getProvisioningEventBus(ui.getSession()).addListener(listener); |
| composite.addDisposeListener(event -> ProvUI.getProvisioningEventBus(ui.getSession()).removeListener(listener)); |
| |
| validateButtons(); |
| } |
| |
| // Details area |
| details = new Text(composite, SWT.READ_ONLY | SWT.WRAP); |
| GridData data = new GridData(SWT.FILL, SWT.FILL, true, false); |
| data.heightHint = convertHeightInCharsToPixels(ILayoutConstants.DEFAULT_SITEDETAILS_HEIGHT); |
| data.widthHint = 1; |
| |
| details.setLayoutData(data); |
| |
| GridLayoutFactory.fillDefaults().numColumns(policy.getRepositoriesVisible() ? 2 : 1).margins(LayoutConstants.getMargins()).spacing(LayoutConstants.getSpacing()).generateLayout(composite); |
| |
| Dialog.applyDialogFont(composite); |
| return composite; |
| } |
| |
| private Button createVerticalButton(Composite parent, String label, boolean defaultButton) { |
| Button button = new Button(parent, SWT.PUSH); |
| button.setText(label); |
| |
| GridData data = setVerticalButtonLayoutData(button); |
| data.horizontalAlignment = GridData.FILL; |
| |
| button.setToolTipText(label); |
| if (defaultButton) { |
| Shell shell = parent.getShell(); |
| if (shell != null) { |
| shell.setDefaultButton(button); |
| } |
| } |
| return button; |
| } |
| |
| private GridData setVerticalButtonLayoutData(Button button) { |
| GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL); |
| int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH); |
| Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); |
| data.widthHint = Math.max(widthHint, minSize.x); |
| button.setLayoutData(data); |
| return data; |
| } |
| |
| private void setTableColumns() { |
| table.setHeaderVisible(true); |
| String[] columnHeaders; |
| if (policy.getRepositoriesVisible()) |
| columnHeaders = new String[] {ProvUIMessages.RepositoryManipulationPage_NameColumnTitle, ProvUIMessages.RepositoryManipulationPage_LocationColumnTitle, ProvUIMessages.RepositoryManipulationPage_EnabledColumnTitle}; |
| else |
| columnHeaders = new String[] {ProvUIMessages.RepositoryManipulationPage_NameColumnTitle, ProvUIMessages.RepositoryManipulationPage_LocationColumnTitle}; |
| for (int i = 0; i < columnHeaders.length; i++) { |
| TableColumn tc = new TableColumn(table, SWT.NONE, i); |
| tc.setResizable(true); |
| tc.setText(columnHeaders[i]); |
| if (i == RepositoryDetailsLabelProvider.COL_ENABLEMENT) { |
| tc.setWidth(convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_SMALL_COLUMN_WIDTH)); |
| tc.setAlignment(SWT.CENTER); |
| } else if (i == RepositoryDetailsLabelProvider.COL_NAME) { |
| tc.setWidth(convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_COLUMN_WIDTH)); |
| } else { |
| tc.setWidth(convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_PRIMARY_COLUMN_WIDTH)); |
| } |
| tc.addSelectionListener(new SelectionListener() { |
| @Override |
| public void widgetDefaultSelected(SelectionEvent e) { |
| columnSelected((TableColumn) e.widget); |
| } |
| |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| columnSelected((TableColumn) e.widget); |
| } |
| |
| }); |
| // First column only |
| if (i == 0) { |
| table.setSortColumn(tc); |
| table.setSortDirection(SWT.UP); |
| } |
| } |
| } |
| |
| private Composite createVerticalButtonBar(Composite parent) { |
| // Create composite. |
| Composite composite = new Composite(parent, SWT.NONE); |
| initializeDialogUnits(composite); |
| |
| // create a layout with spacing and margins appropriate for the font |
| // size. |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 1; |
| layout.marginWidth = 5; |
| layout.marginHeight = 0; |
| layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); |
| layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); |
| composite.setLayout(layout); |
| |
| createVerticalButtons(composite); |
| return composite; |
| } |
| |
| private void createVerticalButtons(Composite parent) { |
| addButton = createVerticalButton(parent, ProvUIMessages.RepositoryManipulationPage_Add, false); |
| addButton.addListener(SWT.Selection, event -> addRepository()); |
| |
| editButton = createVerticalButton(parent, ProvUIMessages.RepositoryManipulationPage_Edit, false); |
| editButton.addListener(SWT.Selection, event -> changeRepositoryProperties()); |
| |
| removeButton = createVerticalButton(parent, ProvUIMessages.RepositoryManipulationPage_Remove, false); |
| removeButton.addListener(SWT.Selection, event -> removeRepositories()); |
| |
| refreshButton = createVerticalButton(parent, ProvUIMessages.RepositoryManipulationPage_RefreshConnection, false); |
| refreshButton.addListener(SWT.Selection, event -> refreshRepository()); |
| |
| disableButton = createVerticalButton(parent, ProvUIMessages.RepositoryManipulationPage_DisableButton, false); |
| disableButton.addListener(SWT.Selection, event -> toggleRepositoryEnablement()); |
| |
| Button button = createVerticalButton(parent, ProvUIMessages.RepositoryManipulationPage_Import, false); |
| button.addListener(SWT.Selection, event -> importRepositories()); |
| |
| exportButton = createVerticalButton(parent, ProvUIMessages.RepositoryManipulationPage_Export, false); |
| exportButton.addListener(SWT.Selection, event -> exportRepositories()); |
| } |
| |
| CachedMetadataRepositories getInput() { |
| if (input == null) |
| input = new CachedMetadataRepositories(); |
| return input; |
| } |
| |
| @Override |
| public boolean performOk() { |
| if (changed) |
| ElementUtils.updateRepositoryUsingElements(ui, getElements()); |
| originalNameCache.clear(); |
| originalURICache.clear(); |
| return super.performOk(); |
| } |
| |
| private StructuredViewerProvisioningListener getViewerProvisioningListener() { |
| return new StructuredViewerProvisioningListener(RepositoryManipulationPage.this.getClass().getName(), repositoryViewer, ProvUIProvisioningListener.PROV_EVENT_METADATA_REPOSITORY, ui.getOperationRunner()) { |
| @Override |
| protected void repositoryDiscovered(RepositoryEvent e) { |
| RepositoryManipulationPage.this.safeRefresh(null); |
| } |
| |
| @Override |
| protected void repositoryChanged(RepositoryEvent e) { |
| RepositoryManipulationPage.this.safeRefresh(null); |
| } |
| }; |
| } |
| |
| MetadataRepositoryElement[] getElements() { |
| return getInput().getElements(); |
| } |
| |
| MetadataRepositoryElement[] getSelectedElements() { |
| Object[] items = repositoryViewer.getStructuredSelection().toArray(); |
| ArrayList<Object> list = new ArrayList<>(items.length); |
| for (int i = 0; i < items.length; i++) { |
| if (items[i] instanceof MetadataRepositoryElement) |
| list.add(items[i]); |
| } |
| return list.toArray(new MetadataRepositoryElement[list.size()]); |
| } |
| |
| void validateButtons() { |
| MetadataRepositoryElement[] elements = getSelectedElements(); |
| exportButton.setEnabled(elements.length > 0); |
| removeButton.setEnabled(elements.length > 0); |
| editButton.setEnabled(elements.length == 1); |
| refreshButton.setEnabled(elements.length == 1); |
| if (elements.length >= 1) { |
| if (toggleMeansDisable(elements)) |
| disableButton.setText(ProvUIMessages.RepositoryManipulationPage_DisableButton); |
| else |
| disableButton.setText(ProvUIMessages.RepositoryManipulationPage_EnableButton); |
| disableButton.setEnabled(true); |
| } else { |
| disableButton.setText(ProvUIMessages.RepositoryManipulationPage_EnableButton); |
| disableButton.setEnabled(false); |
| } |
| } |
| |
| void addRepository() { |
| AddRepositoryDialog dialog = new AddRepositoryDialog(getShell(), ui) { |
| @Override |
| protected RepositoryTracker getRepositoryTracker() { |
| return RepositoryManipulationPage.this.getLocalCacheRepoTracker(); |
| } |
| }; |
| dialog.setTitle(ProvUIMessages.ColocatedRepositoryManipulator_AddSiteOperationLabel); |
| dialog.open(); |
| } |
| |
| void refreshRepository() { |
| final MetadataRepositoryElement[] selected = getSelectedElements(); |
| final ProvisionException[] fail = new ProvisionException[1]; |
| final boolean[] remove = new boolean[1]; |
| remove[0] = false; |
| if (selected.length != 1) |
| return; |
| final URI location = selected[0].getLocation(); |
| ProgressMonitorDialog dialog = new ProgressMonitorDialog(getShell()); |
| try { |
| dialog.run(true, true, monitor -> { |
| monitor.beginTask(NLS.bind(ProvUIMessages.RepositoryManipulationPage_ContactingSiteMessage, location), 100); |
| try { |
| // Batch the events for this operation so that any events on reload (discovery, etc.) will be ignored |
| // in the UI as they happen. |
| ui.signalRepositoryOperationStart(); |
| tracker.clearRepositoryNotFound(location); |
| // If the managers don't know this repo, refreshing it will not work. |
| // We temporarily add it, but we must remove it in case the user cancels out of this page. |
| if (!includesRepo(tracker.getKnownRepositories(ui.getSession()), location)) { |
| remove[0] = true; |
| // We don't want to use the tracker here because it ensures that additions are |
| // reported as user events to be responded to. We don't want, for example, the |
| // install wizard to change combo selections based on what is done here. |
| ProvUI.getMetadataRepositoryManager(ui.getSession()).addRepository(location); |
| ProvUI.getArtifactRepositoryManager(ui.getSession()).addRepository(location); |
| } |
| // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=312332 |
| // We assume repository colocation here. Ideally we should not do this, but the |
| // RepositoryTracker API is swallowing the refresh errors. |
| SubMonitor sub = SubMonitor.convert(monitor, 200); |
| try { |
| ProvUI.getMetadataRepositoryManager(ui.getSession()).refreshRepository(location, sub.newChild(100)); |
| } catch (ProvisionException e1) { |
| fail[0] = e1; |
| } |
| try { |
| ProvUI.getArtifactRepositoryManager(ui.getSession()).refreshRepository(location, sub.newChild(100)); |
| } catch (ProvisionException e2) { |
| // Failure in the artifact repository. We will not report this because the user has no separate visibility |
| // of the artifact repository. We should log the error. If this repository fails during a download, the error |
| // will be reported at that time to the user, when it matters. This also prevents false error reporting when |
| // a metadata repository didn't actually have a colocated artifact repository. |
| LogHelper.log(e2); |
| } |
| } catch (OperationCanceledException e3) { |
| // Catch canceled login attempts |
| fail[0] = new ProvisionException(new Status(IStatus.CANCEL, ProvUIActivator.PLUGIN_ID, ProvUIMessages.RepositoryManipulationPage_RefreshOperationCanceled, e3)); |
| } finally { |
| // Check if the monitor was canceled |
| if (fail[0] == null && monitor.isCanceled()) |
| fail[0] = new ProvisionException(new Status(IStatus.CANCEL, ProvUIActivator.PLUGIN_ID, ProvUIMessages.RepositoryManipulationPage_RefreshOperationCanceled)); |
| // If we temporarily added a repo so we could read it, remove it. |
| if (remove[0]) { |
| ProvUI.getMetadataRepositoryManager(ui.getSession()).removeRepository(location); |
| ProvUI.getArtifactRepositoryManager(ui.getSession()).removeRepository(location); |
| } |
| ui.signalRepositoryOperationComplete(null, false); |
| } |
| }); |
| } catch (InvocationTargetException e) { |
| // nothing to report |
| } catch (InterruptedException e) { |
| // nothing to report |
| } |
| if (fail[0] != null) { |
| // If the repo was not found, tell ProvUI that we will be reporting it. |
| // We are going to report problems directly to the status manager because we |
| // do not want the automatic repo location editing to kick in. |
| if (fail[0].getStatus().getCode() == ProvisionException.REPOSITORY_NOT_FOUND) { |
| tracker.addNotFound(location); |
| } |
| if (!fail[0].getStatus().matches(IStatus.CANCEL)) { |
| // An error is only shown if the dialog was not canceled |
| ProvUI.handleException(fail[0], null, StatusManager.SHOW); |
| } |
| } else { |
| // Confirm that it was successful |
| MessageDialog.openInformation(getShell(), ProvUIMessages.RepositoryManipulationPage_TestConnectionTitle, NLS.bind(ProvUIMessages.RepositoryManipulationPage_TestConnectionSuccess, URIUtil.toUnencodedString(location))); |
| } |
| repositoryViewer.update(selected[0], null); |
| setDetails(); |
| } |
| |
| boolean includesRepo(URI[] repos, URI repo) { |
| for (int i = 0; i < repos.length; i++) |
| if (repos[i].equals(repo)) |
| return true; |
| return false; |
| } |
| |
| void toggleRepositoryEnablement() { |
| MetadataRepositoryElement[] selected = getSelectedElements(); |
| if (selected.length >= 1) { |
| boolean enableSites = !toggleMeansDisable(selected); |
| for (int i = 0; i < selected.length; i++) { |
| selected[i].setEnabled(enableSites); |
| getInput().put(selected[i]); |
| } |
| updateForEnablementChange(selected); |
| } |
| validateButtons(); |
| } |
| |
| void updateForEnablementChange(MetadataRepositoryElement[] updated) { |
| if (comparator.getSortKey() == RepositoryDetailsLabelProvider.COL_ENABLEMENT) |
| repositoryViewer.refresh(true); |
| else |
| for (int i = 0; i < updated.length; i++) |
| repositoryViewer.update(updated[i], null); |
| changed = true; |
| } |
| |
| void importRepositories() { |
| BusyIndicator.showWhile(getShell().getDisplay(), () -> { |
| MetadataRepositoryElement[] imported = UpdateManagerCompatibility.importSites(getShell()); |
| if (imported.length > 0) { |
| changed = true; |
| for (int i = 0; i < imported.length; i++) |
| getInput().put(imported[i]); |
| safeRefresh(null); |
| } |
| }); |
| } |
| |
| void exportRepositories() { |
| BusyIndicator.showWhile(getShell().getDisplay(), () -> { |
| MetadataRepositoryElement[] elements = getSelectedElements(); |
| if (elements.length == 0) |
| elements = getElements(); |
| UpdateManagerCompatibility.exportSites(getShell(), elements); |
| }); |
| } |
| |
| void changeRepositoryProperties() { |
| final MetadataRepositoryElement[] selected = getSelectedElements(); |
| if (selected.length != 1) |
| return; |
| |
| URI originalLocation = null; |
| String originalName = null; |
| if (originalURICache.containsKey(selected[0])) { |
| originalLocation = originalURICache.get(selected[0]); |
| } else |
| originalLocation = selected[0].getLocation(); |
| if (originalNameCache.containsKey(selected[0])) { |
| originalName = originalNameCache.get(selected[0]); |
| } else |
| originalName = selected[0].getName(); |
| final URI existingLocation = originalLocation; |
| RepositoryNameAndLocationDialog dialog = new RepositoryNameAndLocationDialog(getShell(), ui) { |
| @Override |
| protected String getInitialLocationText() { |
| return URIUtil.toUnencodedString(selected[0].getLocation()); |
| } |
| |
| @Override |
| protected String getInitialNameText() { |
| return selected[0].getName(); |
| } |
| |
| @Override |
| protected URI getOriginalLocation() { |
| return existingLocation; |
| } |
| }; |
| |
| int retCode = dialog.open(); |
| if (retCode == Window.OK && dialog.getLocation() != null) { |
| selected[0].setNickname(dialog.getName()); |
| selected[0].setLocation(dialog.getLocation()); |
| if (dialog.getLocation().equals(existingLocation)) { |
| // the change is reverted |
| originalURICache.remove(selected[0]); |
| } else if (!originalURICache.containsKey(selected[0])) |
| originalURICache.put(selected[0], existingLocation); |
| if (dialog.getName().equals(originalName)) { |
| // the change is reverted |
| originalNameCache.remove(selected[0]); |
| } else if (!originalNameCache.containsKey(selected[0])) |
| originalNameCache.put(selected[0], originalName); |
| if (originalURICache.size() > 0 || originalNameCache.size() > 0) |
| changed = true; |
| else |
| changed = false; |
| repositoryViewer.update(selected[0], null); |
| setDetails(); |
| } |
| } |
| |
| void columnSelected(TableColumn tc) { |
| TableColumn[] cols = table.getColumns(); |
| for (int i = 0; i < cols.length; i++) { |
| if (cols[i] == tc) { |
| if (i != comparator.getSortKey()) { |
| comparator.setSortKey(i); |
| table.setSortColumn(tc); |
| comparator.sortAscending(); |
| table.setSortDirection(SWT.UP); |
| } else { |
| if (comparator.isAscending()) { |
| table.setSortDirection(SWT.DOWN); |
| comparator.sortDescending(); |
| } else { |
| table.setSortDirection(SWT.UP); |
| comparator.sortAscending(); |
| } |
| } |
| repositoryViewer.refresh(); |
| break; |
| } |
| } |
| } |
| |
| void safeRefresh(final MetadataRepositoryElement elementToSelect) { |
| Runnable runnable = () -> { |
| repositoryViewer.refresh(); |
| if (elementToSelect != null) |
| repositoryViewer.setSelection(new StructuredSelection(elementToSelect), true); |
| }; |
| if (Display.getCurrent() == null) |
| display.asyncExec(runnable); |
| else |
| runnable.run(); |
| } |
| |
| void applyFilter() { |
| String text = pattern.getText(); |
| if (text == DEFAULT_FILTER_TEXT) |
| text = ""; //$NON-NLS-1$ |
| if (text.length() == 0) |
| filter.setPattern(null); |
| else |
| filter.setPattern(text); |
| if (filterJob != null) |
| filterJob.cancel(); |
| filterJob = new WorkbenchJob("filter job") { //$NON-NLS-1$ |
| @Override |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| if (monitor.isCanceled()) |
| return Status.CANCEL_STATUS; |
| if (!repositoryViewer.getTable().isDisposed()) |
| repositoryViewer.refresh(); |
| return Status.OK_STATUS; |
| } |
| |
| }; |
| filterJob.setSystem(true); |
| filterJob.schedule(FILTER_DELAY); |
| } |
| |
| void setDetails() { |
| MetadataRepositoryElement[] selections = getSelectedElements(); |
| if (selections.length == 1) { |
| details.setText(selections[0].getDescription()); |
| } else { |
| details.setText(""); //$NON-NLS-1$ |
| } |
| } |
| |
| @Override |
| public void init(IWorkbench workbench) { |
| noDefaultAndApplyButton(); |
| if (ui == null) { |
| setProvisioningUI(ProvisioningUI.getDefaultUI()); |
| } |
| } |
| |
| void removeRepositories() { |
| MetadataRepositoryElement[] selections = getSelectedElements(); |
| if (selections.length > 0) { |
| String message = ProvUIMessages.RepositoryManipulationPage_RemoveConfirmMessage; |
| if (selections.length == 1) |
| message = NLS.bind(ProvUIMessages.RepositoryManipulationPage_RemoveConfirmSingleMessage, URIUtil.toUnencodedString(selections[0].getLocation())); |
| if (MessageDialog.openQuestion(getShell(), ProvUIMessages.RepositoryManipulationPage_RemoveConfirmTitle, message)) { |
| |
| changed = true; |
| for (int i = 0; i < selections.length; i++) { |
| getInput().remove(selections[i]); |
| } |
| safeRefresh(null); |
| } |
| } |
| } |
| |
| // Return a repo manipulator that only operates on the local cache. |
| // Labels and other presentation info are used from the original manipulator. |
| RepositoryTracker getLocalCacheRepoTracker() { |
| if (localCacheRepoManipulator == null) |
| localCacheRepoManipulator = new RepositoryTracker() { |
| @Override |
| public void addRepository(URI location, String nickname, ProvisioningSession session) { |
| MetadataRepositoryElement element = getInput().get(location); |
| if (element == null) { |
| element = new MetadataRepositoryElement(getInput(), null, ui, location, true); |
| getInput().put(element); |
| } |
| if (nickname != null) |
| element.setNickname(nickname); |
| changed = true; |
| safeRefresh(element); |
| } |
| |
| @Override |
| public URI[] getKnownRepositories(ProvisioningSession session) { |
| return RepositoryManipulationPage.this.getKnownRepositories(); |
| } |
| |
| @Override |
| public void removeRepositories(URI[] repoLocations, ProvisioningSession session) { |
| RepositoryManipulationPage.this.removeRepositories(); |
| } |
| |
| @Override |
| public void refreshRepositories(URI[] locations, ProvisioningSession session, IProgressMonitor monitor) { |
| // Nothing to refresh in the local cache |
| } |
| |
| @Override |
| public IStatus validateRepositoryLocation(ProvisioningSession session, URI location, boolean contactRepositories, IProgressMonitor monitor) { |
| IStatus status = super.validateRepositoryLocation(session, location, contactRepositories, monitor); |
| if (status.isOK()) { |
| String repoString = URIUtil.toUnencodedString(location); |
| int length = repoString.length(); |
| if (length > 0 && repoString.charAt(length - 1) == '/') { |
| try { |
| location = URIUtil.fromString(repoString.substring(0, length - 1)); |
| } catch (URISyntaxException e) { |
| return status; |
| } |
| status = super.validateRepositoryLocation(session, location, contactRepositories, monitor); |
| } |
| } |
| return status; |
| |
| } |
| }; |
| return localCacheRepoManipulator; |
| } |
| |
| @Override |
| public void copyToClipboard(Control activeControl) { |
| MetadataRepositoryElement[] elements = getSelectedElements(); |
| if (elements.length == 0) |
| elements = getElements(); |
| String text = ""; //$NON-NLS-1$ |
| StringBuffer buffer = new StringBuffer(); |
| for (int i = 0; i < elements.length; i++) { |
| buffer.append(labelProvider.getClipboardText(elements[i], CopyUtils.DELIMITER)); |
| if (i > 0) |
| buffer.append(CopyUtils.NEWLINE); |
| } |
| text = buffer.toString(); |
| |
| if (text.length() == 0) |
| return; |
| Clipboard clipboard = new Clipboard(PlatformUI.getWorkbench().getDisplay()); |
| clipboard.setContents(new Object[] {text}, new Transfer[] {TextTransfer.getInstance()}); |
| clipboard.dispose(); |
| } |
| |
| // If more than half of the selected repos are enabled, toggle means disable. |
| // Otherwise it means enable. |
| private boolean toggleMeansDisable(MetadataRepositoryElement[] elements) { |
| double count = 0; |
| for (int i = 0; i < elements.length; i++) |
| if (elements[i].isEnabled()) |
| count++; |
| return (count / elements.length) > 0.5; |
| } |
| |
| URI[] getKnownRepositories() { |
| MetadataRepositoryElement[] elements = getElements(); |
| URI[] locations = new URI[elements.length]; |
| for (int i = 0; i < elements.length; i++) |
| locations[i] = elements[i].getLocation(); |
| return locations; |
| } |
| } |