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;
15 
16 import java.lang.reflect.InvocationTargetException;
17 import java.util.ArrayList;
18 import java.util.List;
19 
20 import org.eclipse.core.resources.IProject;
21 import org.eclipse.core.runtime.IAdaptable;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.jface.dialogs.*;
24 import org.eclipse.jface.dialogs.Dialog;
25 import org.eclipse.jface.util.PropertyChangeEvent;
26 import org.eclipse.jface.viewers.IStructuredSelection;
27 import org.eclipse.jface.viewers.TableViewer;
28 import org.eclipse.osgi.util.NLS;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.events.SelectionAdapter;
31 import org.eclipse.swt.events.SelectionEvent;
32 import org.eclipse.swt.layout.GridData;
33 import org.eclipse.swt.layout.GridLayout;
34 import org.eclipse.swt.widgets.*;
35 import org.eclipse.team.core.RepositoryProvider;
36 import org.eclipse.team.core.TeamException;
37 import org.eclipse.team.internal.ccvs.core.*;
38 import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
39 import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
40 import org.eclipse.team.internal.ccvs.ui.repo.RepositoryComparator;
41 import org.eclipse.ui.PlatformUI;
42 import org.eclipse.ui.model.WorkbenchContentProvider;
43 import org.eclipse.ui.model.WorkbenchLabelProvider;
44 
45 public class CVSProjectPropertiesPage extends CVSPropertiesPage {
46 	IProject project;
47 	ICVSRepositoryLocation oldLocation;
48 	ICVSRepositoryLocation newLocation = null;
49 
50 	private static final int TABLE_HEIGHT_HINT = 150;
51 
52 	// Widgets
53 	Text methodText;
54 	Text userText;
55 	Text hostText;
56 	Text pathText;
57 	Text moduleText;
58 	Text portText;
59 	Text tagText;
60 	private Button fetchButton;
61 	private Button watchEditButton;
62 
63 	IUserInfo info;
64 	CVSTeamProvider provider;
65 	private boolean fetch;
66 	private boolean watchEdit;
67 
isCompatible(ICVSRepositoryLocation location, ICVSRepositoryLocation oldLocation)68 	public static boolean isCompatible(ICVSRepositoryLocation location,
69 			ICVSRepositoryLocation oldLocation) {
70 		return CVSRepositoryLocationMatcher.isCompatible(location, oldLocation,
71 				false);
72 	}
73 
74 	private class RepositorySelectionDialog extends Dialog {
75 		ICVSRepositoryLocation[] allLocations;
76 		ICVSRepositoryLocation[] compatibleLocations;
77 		ICVSRepositoryLocation selectedLocation;
78 
79 		TableViewer viewer;
80 		Button okButton;
81 		boolean showCompatible = true;
82 
RepositorySelectionDialog(Shell shell, ICVSRepositoryLocation oldLocation)83 		public RepositorySelectionDialog(Shell shell, ICVSRepositoryLocation oldLocation) {
84 			super(shell);
85 			initialize(oldLocation);
86 		}
initialize(ICVSRepositoryLocation oldLocation)87 		private void initialize(ICVSRepositoryLocation oldLocation) {
88 			allLocations = CVSUIPlugin.getPlugin().getRepositoryManager().getKnownRepositoryLocations();
89 			List locations = new ArrayList();
90 			for (ICVSRepositoryLocation location : allLocations) {
91 				if (isCompatible(location, oldLocation)) {
92 					locations.add(location);
93 				}
94 			}
95 			compatibleLocations = (ICVSRepositoryLocation[]) locations.toArray(new ICVSRepositoryLocation[locations.size()]);
96 		}
97 		@Override
createButtonsForButtonBar(Composite parent)98 		protected void createButtonsForButtonBar(Composite parent) {
99 			// create OK and Cancel buttons by default
100 			okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
101 			okButton.setEnabled(false);
102 			createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
103 		}
104 		@Override
createDialogArea(Composite parent)105 		protected Control createDialogArea(Composite parent) {
106 			parent.getShell().setText(CVSUIMessages.CVSProjectPropertiesPage_Select_a_Repository_1);
107 			Composite composite = (Composite) super.createDialogArea(parent);
108 
109 			createLabel(composite, CVSUIMessages.CVSProjectPropertiesPage_Select_a_CVS_repository_location_to_share_the_project_with__2, 1);
110 			Table table = new Table(composite, SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
111 			GridData data = new GridData(GridData.FILL_HORIZONTAL);
112 			data.heightHint = TABLE_HEIGHT_HINT;
113 			table.setLayoutData(data);
114 			viewer = new TableViewer(table);
115 			viewer.setLabelProvider(new WorkbenchLabelProvider());
116 			viewer.setComparator(new RepositoryComparator());
117 			viewer.setContentProvider(new WorkbenchContentProvider() {
118 				@Override
119 				public Object[] getElements(Object inputElement) {
120 					if (showCompatible) {
121 						return compatibleLocations;
122 					} else {
123 						return allLocations;
124 					}
125 				}
126 			});
127 			viewer.addSelectionChangedListener(event -> {
128 				IStructuredSelection selection = event.getStructuredSelection();
129 				if (selection.isEmpty()) {
130 					selectedLocation = null;
131 					okButton.setEnabled(false);
132 				} else {
133 					selectedLocation = (ICVSRepositoryLocation)selection.getFirstElement();
134 					okButton.setEnabled(true);
135 				}
136 			});
137 			viewer.addDoubleClickListener(event -> okPressed());
138 			viewer.setInput(compatibleLocations);
139 
140 			final Button compatibleButton = createCheckBox(composite, CVSUIMessages.CVSProjectPropertiesPage_31);
141 			compatibleButton.setSelection(showCompatible);
142 			compatibleButton.addSelectionListener(new SelectionAdapter() {
143 				@Override
144 				public void widgetSelected(SelectionEvent e) {
145 					showCompatible = compatibleButton.getSelection();
146 					viewer.refresh();
147 				}
148 			});
149 
150 			Dialog.applyDialogFont(parent);
151 
152 			return composite;
153 		}
154 		@Override
cancelPressed()155 		protected void cancelPressed() {
156 			selectedLocation = null;
157 			super.cancelPressed();
158 		}
getLocation()159 		public ICVSRepositoryLocation getLocation() {
160 			return selectedLocation;
161 		}
162 	}
163 
164 	@Override
createContents(Composite parent)165 	protected Control createContents(Composite parent) {
166 		initialize();
167 
168 		Composite composite = new Composite(parent, SWT.NULL);
169 		composite.setLayoutData(new GridData(GridData.FILL_BOTH));
170 		GridLayout layout = new GridLayout();
171 		layout.numColumns = 2;
172 		composite.setLayout(layout);
173 
174 		Label label = createLabel(composite, CVSUIMessages.CVSProjectPropertiesPage_connectionType, 1);
175 		methodText= createReadOnlyText(composite, ""); //$NON-NLS-1$
176 
177 		label = createLabel(composite, CVSUIMessages.CVSProjectPropertiesPage_user, 1);
178 		userText= createReadOnlyText(composite, ""); //$NON-NLS-1$
179 
180 		label = createLabel(composite, CVSUIMessages.CVSRepositoryLocationPropertySource_host, 1);
181 		hostText= createReadOnlyText(composite, ""); //$NON-NLS-1$
182 
183 		label = createLabel(composite, CVSUIMessages.CVSPropertiesPage_port, 1);
184 		portText= createReadOnlyText(composite, ""); //$NON-NLS-1$
185 
186 		label = createLabel(composite, CVSUIMessages.CVSRepositoryLocationPropertySource_root, 1);
187 		pathText= createReadOnlyText(composite, ""); //$NON-NLS-1$
188 
189 		label = createLabel(composite, CVSUIMessages.CVSPropertiesPage_module, 1);
190 		moduleText= createReadOnlyText(composite, ""); //$NON-NLS-1$
191 
192 		label = createLabel(composite, CVSUIMessages.CVSPropertiesPage_tag, 1);
193 		tagText= createReadOnlyText(composite, ""); //$NON-NLS-1$
194 
195 		createLabel(composite, "", 1); //$NON-NLS-1$
196 
197 		// Should absent directories be fetched on update
198 		fetchButton = createCheckBox(composite, CVSUIMessages.CVSProjectPropertiesPage_fetchAbsentDirectoriesOnUpdate);
199 		fetchButton.addListener(SWT.Selection, event -> fetch = fetchButton.getSelection());
200 
201 		// Should the project be configured for watch/edit
202 		watchEditButton = createCheckBox(composite, CVSUIMessages.CVSProjectPropertiesPage_configureForWatchEdit);
203 		watchEditButton.addListener(SWT.Selection, event -> watchEdit = watchEditButton.getSelection());
204 
205 		createLabel(composite, "", 1); //$NON-NLS-1$
206 		createLabel(composite, "", 1); //$NON-NLS-1$
207 		createLabel(composite, "", 1); //$NON-NLS-1$
208 		createLabel(composite, "", 1); //$NON-NLS-1$
209 
210 		label = new Label(composite, SWT.WRAP);
211 		label.setText(CVSUIMessages.CVSProjectPropertiesPage_You_can_change_the_sharing_of_this_project_to_another_repository_location__However__this_is_only_possible_if_the_new_location_is___compatible____on_the_same_host_with_the_same_repository_path___1);
212 		GridData data = new GridData(GridData.FILL_HORIZONTAL);
213 		data.widthHint = 200;
214 		data.horizontalSpan = 2;
215 		label.setLayoutData(data);
216 
217 		Button changeButton = new Button(composite, SWT.PUSH);
218 		changeButton.setText(CVSUIMessages.CVSProjectPropertiesPage_Change_Sharing_5);
219 		changeButton.addListener(SWT.Selection, e -> {
220 			RepositorySelectionDialog dialog = new RepositorySelectionDialog(getShell(), oldLocation);
221 			dialog.open();
222 			ICVSRepositoryLocation location = dialog.getLocation();
223 			if (location == null) return;
224 			newLocation = location;
225 			initializeValues(newLocation);
226 		});
227 
228 		initializeValues(oldLocation);
229 		PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IHelpContextIds.PROJECT_PROPERTY_PAGE);
230 		Dialog.applyDialogFont(parent);
231 		return composite;
232 	}
233 	/**
234 	 * Utility method that creates a label instance
235 	 * and sets the default layout data.
236 	 *
237 	 * @param parent  the parent for the new label
238 	 * @param text  the text for the new label
239 	 * @return the new label
240 	 */
241 	@Override
createLabel(Composite parent, String text, int span)242 	protected Label createLabel(Composite parent, String text, int span) {
243 		Label label = new Label(parent, SWT.LEFT);
244 		label.setText(text);
245 		GridData data = new GridData();
246 		data.horizontalSpan = span;
247 		data.horizontalAlignment = GridData.FILL;
248 		label.setLayoutData(data);
249 		return label;
250 	}
251 
252 	/**
253 	 * Creates a new checkbox instance and sets the default layout data.
254 	 *
255 	 * @param group  the composite in which to create the checkbox
256 	 * @param label  the string to set into the checkbox
257 	 * @return the new checkbox
258 	 */
createCheckBox(Composite group, String label)259 	protected Button createCheckBox(Composite group, String label) {
260 		Button button = new Button(group, SWT.CHECK | SWT.LEFT);
261 		button.setText(label);
262 		GridData data = new GridData();
263 		data.horizontalSpan = 2;
264 		button.setLayoutData(data);
265 		return button;
266 	}
267 	/**
268 	 * Initializes the page
269 	 */
initialize()270 	private void initialize() {
271 		// Get the project that is the source of this property page
272 		project = null;
273 		IAdaptable element = getElement();
274 		if (element instanceof IProject) {
275 			project = (IProject)element;
276 		} else {
277 			Object adapter = element.getAdapter(IProject.class);
278 			if (adapter instanceof IProject) {
279 				project = (IProject)adapter;
280 			}
281 		}
282 		// Do some pre-checks to ensure we're in a good state
283 		provider = (CVSTeamProvider)RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId());
284 		if (provider == null) return;
285 		CVSWorkspaceRoot cvsRoot = provider.getCVSWorkspaceRoot();
286 		try {
287 			oldLocation = cvsRoot.getRemoteLocation();
288 			fetch = provider.getFetchAbsentDirectories();
289 			watchEdit = provider.isWatchEditEnabled();
290 		} catch (TeamException e) {
291 			handle(e);
292 		}
293 	}
294 	/**
295 	 * Set the initial values of the widgets
296 	 */
initializeValues(ICVSRepositoryLocation location)297 	private void initializeValues(ICVSRepositoryLocation location) {
298 		if (provider == null) return;
299 		CVSWorkspaceRoot cvsRoot = provider.getCVSWorkspaceRoot();
300 		ICVSFolder folder = cvsRoot.getLocalRoot();
301 
302 		try {
303 			if (!folder.isCVSFolder()) return;
304 			methodText.setText(location.getMethod().getName());
305 			info = location.getUserInfo(true);
306 			userText.setText(info.getUsername());
307 			hostText.setText(location.getHost());
308 			int port = location.getPort();
309 			if (port == ICVSRepositoryLocation.USE_DEFAULT_PORT) {
310 				portText.setText(CVSUIMessages.CVSPropertiesPage_defaultPort);
311 			} else {
312 				portText.setText("" + port); //$NON-NLS-1$
313 			}
314 			pathText.setText(location.getRootDirectory());
315 			FolderSyncInfo syncInfo = folder.getFolderSyncInfo();
316 			if (syncInfo == null) return;
317 			String label = syncInfo.getRepository();
318 			if (label.equals(FolderSyncInfo.VIRTUAL_DIRECTORY)) {
319 				label = NLS.bind(CVSUIMessages.CVSPropertiesPage_virtualModule, new String[] { label });
320 			}
321 			moduleText.setText(label);
322 			fetchButton.setSelection(fetch);
323 			watchEditButton.setSelection(watchEdit);
324 		} catch (TeamException e) {
325 			handle(e);
326 		}
327 
328 		initializeTag();
329 	}
330 
initializeTag()331 	private void initializeTag() {
332 		provider = (CVSTeamProvider)RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId());
333 		if (provider == null) return;
334 		try {
335 			ICVSFolder local = CVSWorkspaceRoot.getCVSFolderFor(project);
336 			CVSTag tag = local.getFolderSyncInfo().getTag();
337 
338 			tagText.setText(getTagLabel(tag));
339 
340 		} catch (TeamException e) {
341 			handle(e);
342 		}
343 	}
344 	@Override
performOk()345 	public boolean performOk() {
346 		final boolean[] changeReadOnly = { false };
347 		try {
348 			if (fetch != provider.getFetchAbsentDirectories())
349 				provider.setFetchAbsentDirectories(fetch);
350 			if (watchEdit != provider.isWatchEditEnabled()) {
351 				provider.setWatchEditEnabled(watchEdit);
352 				changeReadOnly[0] = true;
353 			}
354 		} catch (CVSException e) {
355 			handle(e);
356 		}
357 		if (newLocation == null && !changeReadOnly[0]) {
358 			return true;
359 		}
360 		try {
361 			if (newLocation != null && !isCompatible(newLocation, oldLocation)) {
362 				if (!MessageDialog.openQuestion(getShell(), CVSUIMessages.CVSProjectPropertiesPage_32, CVSUIMessages.CVSProjectPropertiesPage_33)) { //
363 					return false;
364 				}
365 			}
366 			new ProgressMonitorDialog(getShell()).run(true, true, monitor -> {
367 				try {
368 					monitor.beginTask(CVSUIMessages.CVSProjectPropertiesPage_progressTaskName,
369 					((newLocation == null)?0:100) + (changeReadOnly[0]?100:0));
370 					if (newLocation != null)
371 						provider.setRemoteRoot(newLocation, Policy.subMonitorFor(monitor, 100));
372 					if (changeReadOnly[0])
373 						setReadOnly(watchEdit, Policy.infiniteSubMonitorFor(monitor, 100));
374 				} catch (TeamException e) {
375 					throw new InvocationTargetException(e);
376 				}
377 			});
378 			newLocation = null;
379 			if (changeReadOnly[0]) {
380 				CVSUIPlugin.broadcastPropertyChange(new PropertyChangeEvent(this, CVSUIPlugin.P_DECORATORS_CHANGED, null, null));
381 			}
382 		} catch (InvocationTargetException e) {
383 			handle(e);
384 		} catch (InterruptedException e) {
385 			return false;
386 		}
387 
388 		return true;
389 	}
390 	/**
391 	 * @param watchEdit
392 	 */
setReadOnly(final boolean watchEdit, final IProgressMonitor monitor)393 	protected void setReadOnly(final boolean watchEdit, final IProgressMonitor monitor) throws CVSException {
394 		monitor.beginTask(null, 512);
395 		String taskName = watchEdit?
396 			CVSUIMessages.CVSProjectPropertiesPage_setReadOnly:
397 			CVSUIMessages.CVSProjectPropertiesPage_clearReadOnly;
398 		monitor.subTask(taskName);
399 		ICVSFolder root = CVSWorkspaceRoot.getCVSFolderFor(project);
400 		root.accept(new ICVSResourceVisitor() {
401 			@Override
402 			public void visitFile(ICVSFile file) throws CVSException {
403 				// only change managed, unmodified files
404 				if (file.isManaged() && !file.isModified(null))
405 					file.setReadOnly(watchEdit);
406 				monitor.worked(1);
407 			}
408 
409 			@Override
410 			public void visitFolder(ICVSFolder folder) throws CVSException {
411 				folder.acceptChildren(this);
412 			}
413 		});
414 		monitor.done();
415 	}
416 	/**
417 	 * Shows the given errors to the user.
418 	 */
handle(Throwable t)419 	protected void handle(Throwable t) {
420 		CVSUIPlugin.openError(getShell(), null, null, t);
421 	}
422 }
423 
424