1 /******************************************************************************* 2 * Copyright (c) 2000, 2018 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.team.internal.ccvs.ui.repo; 15 16 17 import java.util.Properties; 18 19 import org.eclipse.core.runtime.IStatus; 20 import org.eclipse.jface.action.*; 21 import org.eclipse.jface.dialogs.IDialogSettings; 22 import org.eclipse.jface.util.IPropertyChangeListener; 23 import org.eclipse.jface.viewers.*; 24 import org.eclipse.jface.wizard.WizardDialog; 25 import org.eclipse.osgi.util.NLS; 26 import org.eclipse.swt.SWT; 27 import org.eclipse.swt.dnd.*; 28 import org.eclipse.swt.events.KeyAdapter; 29 import org.eclipse.swt.events.KeyEvent; 30 import org.eclipse.swt.widgets.*; 31 import org.eclipse.team.core.TeamException; 32 import org.eclipse.team.internal.ccvs.core.*; 33 import org.eclipse.team.internal.ccvs.core.util.KnownRepositories; 34 import org.eclipse.team.internal.ccvs.ui.*; 35 import org.eclipse.team.internal.ccvs.ui.model.AllRootsElement; 36 import org.eclipse.team.internal.ccvs.ui.wizards.NewLocationWizard; 37 import org.eclipse.team.internal.core.TeamPlugin; 38 import org.eclipse.team.internal.ui.actions.TeamAction; 39 import org.eclipse.ui.*; 40 import org.eclipse.ui.actions.ActionFactory; 41 import org.eclipse.ui.dialogs.PropertyDialogAction; 42 import org.eclipse.ui.part.PluginTransfer; 43 import org.eclipse.ui.part.PluginTransferData; 44 45 /** 46 * RepositoriesView is a view on a set of known CVS repositories 47 * which allows navigation of the structure of the repository and 48 * the performing of CVS-specific operations on the repository contents. 49 */ 50 public class RepositoriesView extends RemoteViewPart { 51 public static final String VIEW_ID = "org.eclipse.team.ccvs.ui.RepositoriesView"; //$NON-NLS-1$ 52 53 // The root 54 private AllRootsElement root; 55 56 // Actions 57 private IAction removeAction; 58 private Action newAction; 59 private Action newAnonAction; 60 private PropertyDialogAction propertiesAction; 61 private RemoveRootAction removeRootAction; 62 private RemoveDateTagAction removeDateTagAction; 63 private RepositoriesFilterAction repositoriesFilterAction; 64 private IAction toggleFilterAction; 65 66 private RepositoriesSortingActionGroup repositoriesSortingActionGroup; 67 private IDialogSettings dialogSettings; 68 private static final String SELECTED_ORDER_BY = "selectedOrderBy"; //$NON-NLS-1$ 69 private static final String SELECTED_SORTING_ORDER = "selectedSortingOrder"; //$NON-NLS-1$ 70 private RepositoryComparator savedComparator; 71 private RepositoriesFilter repositoriesFilter; 72 private static final String FILTER_SHOW_MODULES = "filterShowModules"; //$NON-NLS-1$ 73 74 IRepositoryListener listener = new IRepositoryListener() { 75 @Override 76 public void repositoryAdded(final ICVSRepositoryLocation root) { 77 getViewer().getControl().getDisplay().asyncExec(() -> { 78 refreshViewer(); 79 getViewer().setSelection(new StructuredSelection(root)); 80 }); 81 } 82 @Override 83 public void repositoriesChanged(ICVSRepositoryLocation[] roots) { 84 refresh(); 85 } 86 private void refresh() { 87 Display display = getViewer().getControl().getDisplay(); 88 display.asyncExec(() -> RepositoriesView.this.refreshViewer()); 89 } 90 }; 91 92 private static final class RepositoryDragSourceListener implements DragSourceListener { 93 private IStructuredSelection selection; 94 95 @Override dragStart(DragSourceEvent event)96 public void dragStart(DragSourceEvent event) { 97 if(selection!=null) { 98 final Object[] array = selection.toArray(); 99 // event.doit = Utils.getResources(array).length > 0; 100 for (Object a : array) { 101 if (a instanceof ICVSRemoteFile) { 102 event.doit = true; 103 return; 104 } 105 } 106 event.doit = false; 107 } 108 } 109 110 @Override dragSetData(DragSourceEvent event)111 public void dragSetData(DragSourceEvent event) { 112 if (selection!=null && CVSResourceTransfer.getInstance().isSupportedType(event.dataType)) { 113 final Object[] array = selection.toArray(); 114 for (Object a : array) { 115 if (a instanceof ICVSRemoteFile) { 116 event.data = a; 117 return; 118 } 119 } 120 } else if (PluginTransfer.getInstance().isSupportedType(event.dataType)) { 121 final Object[] array = selection.toArray(); 122 for (Object a : array) { 123 if (a instanceof ICVSRemoteFile) { 124 event.data = new PluginTransferData("org.eclipse.team.cvs.ui.cvsRemoteDrop", CVSResourceTransfer.getInstance().toByteArray((ICVSRemoteFile) a)); //$NON-NLS-1$ 125 return; 126 } 127 } 128 129 } 130 } 131 132 @Override dragFinished( DragSourceEvent event)133 public void dragFinished( DragSourceEvent event) { 134 } 135 updateSelection( IStructuredSelection selection)136 public void updateSelection( IStructuredSelection selection) { 137 this.selection = selection; 138 } 139 } 140 141 RepositoryDragSourceListener repositoryDragSourceListener; 142 143 /** 144 * Constructor for RepositoriesView. 145 */ RepositoriesView()146 public RepositoriesView() { 147 super(VIEW_ID); 148 IDialogSettings workbenchSettings = CVSUIPlugin.getPlugin().getDialogSettings(); 149 dialogSettings = workbenchSettings.getSection(VIEW_ID); 150 if (dialogSettings == null) { 151 dialogSettings = workbenchSettings.addNewSection(VIEW_ID); 152 } 153 154 try { 155 // parse the values 156 String selectedOrderBy = dialogSettings.get(SELECTED_ORDER_BY); 157 String selectedSortingOrder = dialogSettings.get(SELECTED_SORTING_ORDER); 158 159 int orderBy = Integer.parseInt(selectedOrderBy); 160 boolean ascending = Boolean.valueOf(selectedSortingOrder).booleanValue(); 161 162 savedComparator = new RepositoryComparator(orderBy, ascending); 163 } catch (NumberFormatException e) { 164 // use default comparator 165 savedComparator = new RepositoryComparator( 166 RepositoryComparator.ORDER_BY_LABEL, true); 167 } 168 169 if (dialogSettings.get(FILTER_SHOW_MODULES) != null && !dialogSettings.get(FILTER_SHOW_MODULES).equals("")) //$NON-NLS-1$ 170 repositoriesFilter = new RepositoriesFilter(dialogSettings.getBoolean(FILTER_SHOW_MODULES)); 171 } 172 173 /** 174 * Contribute actions to the view 175 */ 176 @Override contributeActions()177 protected void contributeActions() { 178 179 final Shell shell = getShell(); 180 181 // Create actions 182 183 // New Repository (popup) 184 newAction = new Action(CVSUIMessages.RepositoriesView_new, CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_NEWLOCATION)) { 185 @Override 186 public void run() { 187 NewLocationWizard wizard = new NewLocationWizard(); 188 wizard.setSwitchPerspectives(false); 189 WizardDialog dialog = new WizardDialog(shell, wizard); 190 dialog.open(); 191 } 192 }; 193 PlatformUI.getWorkbench().getHelpSystem().setHelp(newAction, IHelpContextIds.NEW_REPOSITORY_LOCATION_ACTION); 194 195 if (includeAnonConnection()) { 196 newAnonAction = new Action(CVSUIMessages.RepositoriesView_newAnonCVS, CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_NEWLOCATION)) { 197 @Override 198 public void run() { 199 Properties p = new Properties(); 200 p.setProperty("connection", "pserver"); //$NON-NLS-1$ //$NON-NLS-2$ 201 p.setProperty("user", "anonymous"); //$NON-NLS-1$ //$NON-NLS-2$ 202 p.setProperty("host", "dev.eclipse.org"); //$NON-NLS-1$ //$NON-NLS-2$ 203 p.setProperty("root", "/cvsroot/eclipse"); //$NON-NLS-1$ //$NON-NLS-2$ 204 NewLocationWizard wizard = new NewLocationWizard(p); 205 wizard.setSwitchPerspectives(false); 206 WizardDialog dialog = new WizardDialog(shell, wizard); 207 dialog.open(); 208 } 209 }; 210 PlatformUI.getWorkbench().getHelpSystem().setHelp(newAnonAction, IHelpContextIds.NEW_DEV_ECLIPSE_REPOSITORY_LOCATION_ACTION); 211 } 212 213 // Properties 214 propertiesAction = new PropertyDialogAction(shell, getViewer()); 215 getViewSite().getActionBars().setGlobalActionHandler(ActionFactory.PROPERTIES.getId(), propertiesAction); 216 IStructuredSelection selection = getViewer().getStructuredSelection(); 217 if (selection.size() == 1 && selection.getFirstElement() instanceof RepositoryRoot) { 218 propertiesAction.setEnabled(true); 219 } else { 220 propertiesAction.setEnabled(false); 221 } 222 getViewer().addSelectionChangedListener(event -> { 223 IStructuredSelection ss = event.getStructuredSelection(); 224 boolean enabled = ss.size() == 1 && ss.getFirstElement() instanceof RepositoryRoot; 225 propertiesAction.setEnabled(enabled); 226 }); 227 removeRootAction = new RemoveRootAction(viewer.getControl().getShell(), this); 228 removeRootAction.selectionChanged((IStructuredSelection)null); 229 removeDateTagAction = new RemoveDateTagAction(); 230 removeDateTagAction.selectionChanged( (IStructuredSelection)null); 231 removeAction = new Action(){ 232 @Override 233 public void run(){ 234 if(removeRootAction.isEnabled()){ 235 removeRootAction.run(); 236 } 237 if(removeDateTagAction.isEnabled()){ 238 removeDateTagAction.run(); 239 } 240 } 241 }; 242 PlatformUI.getWorkbench().getHelpSystem().setHelp(removeRootAction, IHelpContextIds.REMOVE_REPOSITORY_LOCATION_ACTION); 243 IActionBars bars = getViewSite().getActionBars(); 244 bars.setGlobalActionHandler(ActionFactory.DELETE.getId(), removeAction); 245 246 // Sort By action group 247 IPropertyChangeListener comparatorUpdater = event -> { 248 String property = event.getProperty(); 249 if (RepositoriesSortingActionGroup.CHANGE_COMPARATOR 250 .equals(property)) { 251 Object newValue = event.getNewValue(); 252 getViewer().refresh(); 253 saveSelectedComparator((RepositoryComparator) newValue); 254 } 255 }; 256 setActionGroup(new RepositoriesSortingActionGroup(shell, 257 comparatorUpdater)); 258 // restore comparator selection 259 getRepositoriesSortingActionGroup().setSelectedComparator( 260 savedComparator); 261 262 super.contributeActions(); 263 264 toggleFilterAction = new Action(CVSUIMessages.RepositoriesView_NoFilter){ 265 @Override 266 public void run(){ 267 if (repositoriesFilter != null) 268 getViewer().removeFilter(repositoriesFilter); 269 repositoriesFilter = null; 270 toggleFilterAction.setEnabled(false); 271 repositoriesFilterAction.setFilter(repositoriesFilter); 272 } 273 }; 274 toggleFilterAction.setEnabled(repositoriesFilter != null); 275 276 //Create the filter action 277 repositoriesFilterAction = new RepositoriesFilterAction(this); 278 repositoriesFilterAction.setText(CVSUIMessages.RepositoriesView_FilterOn); 279 repositoriesFilterAction.init(getViewer()); 280 repositoriesFilterAction.setFilter(repositoriesFilter); 281 repositoriesFilterAction.setToolTipText(CVSUIMessages.RepositoriesView_FilterRepositoriesTooltip); 282 repositoriesFilterAction.setImageDescriptor(CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_FILTER_HISTORY)); 283 284 IMenuManager actionBarsMenu = bars.getMenuManager(); 285 if (actionBarsMenu != null){ 286 actionBarsMenu.add(new Separator()); 287 actionBarsMenu.add(repositoriesFilterAction); 288 actionBarsMenu.add(toggleFilterAction); 289 } 290 } 291 saveSelectedComparator(RepositoryComparator selectedComparator)292 private void saveSelectedComparator(RepositoryComparator selectedComparator) { 293 if (dialogSettings != null) { 294 dialogSettings.put(SELECTED_ORDER_BY, selectedComparator.getOrderBy()); 295 dialogSettings.put(SELECTED_SORTING_ORDER, selectedComparator.isAscending()); 296 } 297 } 298 299 /** 300 * Returns the action group. 301 * 302 * @return the action group 303 */ getRepositoriesSortingActionGroup()304 private RepositoriesSortingActionGroup getRepositoriesSortingActionGroup() { 305 return repositoriesSortingActionGroup; 306 } 307 308 /** 309 * Sets the action group. 310 * 311 * @param actionGroup the action group 312 */ setActionGroup(RepositoriesSortingActionGroup actionGroup)313 private void setActionGroup(RepositoriesSortingActionGroup actionGroup) { 314 this.repositoriesSortingActionGroup = actionGroup; 315 } 316 317 /** 318 * Method includeEclipseConnection. 319 * @return boolean 320 */ includeAnonConnection()321 private boolean includeAnonConnection() { 322 return System.getProperty("eclipse.cvs.anon") != null; //$NON-NLS-1$ 323 } 324 325 @Override addWorkbenchActions(IMenuManager manager)326 protected void addWorkbenchActions(IMenuManager manager) { 327 // New actions go next 328 MenuManager sub = new MenuManager(CVSUIMessages.RepositoriesView_newSubmenu, IWorkbenchActionConstants.GROUP_ADD); 329 manager.add(sub); 330 super.addWorkbenchActions(manager); 331 IStructuredSelection selection = getViewer().getStructuredSelection(); 332 333 removeRootAction.selectionChanged(selection); 334 removeDateTagAction.selectionChanged(selection); 335 if(removeRootAction.isEnabled()) { 336 manager.add(removeRootAction); 337 } 338 if(removeDateTagAction.isEnabled()){ 339 manager.add(removeDateTagAction); 340 } 341 if (selection.size() == 1 && selection.getFirstElement() instanceof RepositoryRoot) { 342 manager.add(new Separator()); 343 manager.add(propertiesAction); 344 } 345 sub.add(newAction); 346 if (newAnonAction != null) 347 sub.add(newAnonAction); 348 sub.add(new Separator("group1")); //$NON-NLS-1$ 349 } 350 351 @Override createPartControl(Composite parent)352 public void createPartControl(Composite parent) { 353 super.createPartControl(parent); 354 CVSUIPlugin.getPlugin().getRepositoryManager().addRepositoryListener(listener); 355 // We need to set comparator on the viewer, in order to modify it by 356 // repositoriesSortingActionGroup in the future. It's the same object 357 getViewer().setComparator(savedComparator); 358 if (repositoriesFilter != null) 359 getViewer().addFilter(repositoriesFilter); 360 getRepositoriesSortingActionGroup().fillActionBars(getViewSite().getActionBars()); 361 } 362 363 @Override dispose()364 public void dispose() { 365 if (repositoriesFilter != null) 366 dialogSettings.put(FILTER_SHOW_MODULES, repositoriesFilter.isShowModules()); 367 else 368 dialogSettings.put(FILTER_SHOW_MODULES, (String) null); 369 CVSUIPlugin.getPlugin().getRepositoryManager().removeRepositoryListener(listener); 370 if (getRepositoriesSortingActionGroup() != null) { 371 getRepositoriesSortingActionGroup().dispose(); 372 } 373 super.dispose(); 374 } 375 376 /** 377 * Initialize the repositories and actions 378 */ initialize()379 private void initialize() { 380 root = new AllRootsElement(); 381 } 382 383 @Override initializeListeners()384 protected void initializeListeners() { 385 super.initializeListeners(); 386 viewer.addSelectionChangedListener(removeRootAction); 387 viewer.addSelectionChangedListener(removeDateTagAction); 388 viewer.addSelectionChangedListener(event -> { 389 IStructuredSelection selection = (IStructuredSelection)event.getSelection(); 390 handleChange(selection); 391 }); 392 393 repositoryDragSourceListener = new RepositoryDragSourceListener(); 394 viewer.addDragSupport( DND.DROP_LINK | DND.DROP_DEFAULT, 395 new Transfer[] { CVSResourceTransfer.getInstance(),PluginTransfer.getInstance()}, 396 repositoryDragSourceListener); 397 } 398 399 @Override getTreeInput()400 protected Object getTreeInput() { 401 initialize(); 402 return root; 403 } 404 405 @Override selectionChanged(IWorkbenchPart part, ISelection selection)406 public void selectionChanged(IWorkbenchPart part, ISelection selection) { 407 String msg = getStatusLineMessage(selection); 408 getViewSite().getActionBars().getStatusLineManager().setMessage(msg); 409 } 410 getStatusLineMessage(ISelection selection)411 private String getStatusLineMessage(ISelection selection) { 412 if (selection==null || selection.isEmpty()) return ""; //$NON-NLS-1$ 413 if (!(selection instanceof IStructuredSelection)) return ""; //$NON-NLS-1$ 414 IStructuredSelection s = (IStructuredSelection)selection; 415 416 if (s.size() > 1) 417 return NLS.bind(CVSUIMessages.RepositoriesView_NItemsSelected, new String[] { String.valueOf(s.size()) }); 418 Object element = TeamAction.getAdapter(s.getFirstElement(), ICVSResource.class); 419 if (element instanceof ICVSRemoteResource) { 420 ICVSRemoteResource res = (ICVSRemoteResource)element; 421 String name; 422 if (res.isContainer()) { 423 name = res.getRepositoryRelativePath(); 424 } else { 425 try { 426 name = res.getRepositoryRelativePath() + " " + ((ICVSRemoteFile)res).getRevision(); //$NON-NLS-1$ 427 } catch (TeamException e) { 428 TeamPlugin.log(IStatus.ERROR, CVSUIMessages.RepositoriesView_CannotGetRevision, e); 429 name = res.getRepositoryRelativePath(); 430 } 431 } 432 return NLS.bind(CVSUIMessages.RepositoriesView_ResourceInRepository, new String[] { name, res.getRepository().getLocation(true) }); 433 } 434 return CVSUIMessages.RepositoriesView_OneItemSelected; 435 } 436 437 @Override getHelpContextId()438 protected String getHelpContextId() { 439 return IHelpContextIds.REPOSITORIES_VIEW; 440 } 441 442 @Override getKeyListener()443 protected KeyAdapter getKeyListener() { 444 return new KeyAdapter() { 445 @Override 446 public void keyPressed(KeyEvent event) { 447 if (event.keyCode == SWT.F5) { 448 if (WorkbenchUserAuthenticator.USE_ALTERNATE_PROMPTER) { 449 ICVSRepositoryLocation[] locations = KnownRepositories.getInstance().getRepositories(); 450 for (ICVSRepositoryLocation location : locations) { 451 location.flushUserInfo(); 452 } 453 } else { 454 refreshAll(); 455 } 456 } else if (event.keyCode == SWT.F9 && WorkbenchUserAuthenticator.USE_ALTERNATE_PROMPTER) { 457 refreshAll(); 458 } 459 } 460 }; 461 } 462 463 private void handleChange(IStructuredSelection selection){ 464 removeRootAction.updateSelection(selection); 465 removeDateTagAction.updateSelection(selection); 466 removeAction.setEnabled(removeRootAction.isEnabled() || removeDateTagAction.isEnabled()); 467 468 repositoryDragSourceListener.updateSelection(selection); 469 } 470 471 public void showFilter(RepositoriesFilter filter) { 472 if (repositoriesFilter != null) 473 getViewer().removeFilter(repositoriesFilter); 474 repositoriesFilter = filter; 475 getViewer().addFilter(filter); 476 toggleFilterAction.setEnabled(true); 477 } 478 479 } 480