1 /******************************************************************************* 2 * Copyright (c) 2014, 2017 Rapicorp 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 * Rapicorp Corporation - initial API and implementation 13 * Martin Karpisek <martin.karpisek@gmail.com> - Bug 351356 14 *******************************************************************************/ 15 package org.eclipse.pde.internal.ui.editor.product; 16 17 import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter; 18 19 import java.net.MalformedURLException; 20 import java.net.URL; 21 import org.eclipse.core.runtime.IStatus; 22 import org.eclipse.core.runtime.Status; 23 import org.eclipse.equinox.internal.p2.ui.dialogs.TextURLDropAdapter; 24 import org.eclipse.jface.dialogs.IDialogConstants; 25 import org.eclipse.jface.dialogs.StatusDialog; 26 import org.eclipse.jface.viewers.*; 27 import org.eclipse.jface.window.Window; 28 import org.eclipse.pde.core.IModelChangedEvent; 29 import org.eclipse.pde.internal.core.iproduct.*; 30 import org.eclipse.pde.internal.ui.*; 31 import org.eclipse.pde.internal.ui.editor.*; 32 import org.eclipse.pde.internal.ui.parts.TablePart; 33 import org.eclipse.swt.SWT; 34 import org.eclipse.swt.custom.CCombo; 35 import org.eclipse.swt.custom.TableEditor; 36 import org.eclipse.swt.dnd.*; 37 import org.eclipse.swt.events.ControlEvent; 38 import org.eclipse.swt.events.ControlListener; 39 import org.eclipse.swt.graphics.Image; 40 import org.eclipse.swt.layout.GridData; 41 import org.eclipse.swt.layout.GridLayout; 42 import org.eclipse.swt.widgets.*; 43 import org.eclipse.ui.actions.ActionFactory; 44 import org.eclipse.ui.forms.widgets.FormToolkit; 45 import org.eclipse.ui.forms.widgets.Section; 46 47 public class UpdatesSection extends TableSection { 48 49 private class RepositoryDialog extends StatusDialog { 50 private Text fLocation; 51 private IRepositoryInfo fEdit; 52 RepositoryDialog(Shell shell, IRepositoryInfo repo)53 public RepositoryDialog(Shell shell, IRepositoryInfo repo) { 54 super(shell); 55 fEdit = repo; 56 setTitle(PDEUIMessages.UpdatesSection_RepositoryDialogTitle); 57 } 58 59 @Override createDialogArea(Composite parent)60 protected Control createDialogArea(Composite parent) { 61 Composite comp = (Composite) super.createDialogArea(parent); 62 ((GridLayout) comp.getLayout()).numColumns = 2; 63 SWTFactory.createLabel(comp, PDEUIMessages.UpdatesSection_Location, 1); 64 fLocation = SWTFactory.createSingleText(comp, 1); 65 GridData data = new GridData(GridData.FILL_HORIZONTAL); 66 data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.ENTRY_FIELD_WIDTH); 67 fLocation.setLayoutData(data); 68 DropTarget target = new DropTarget(fLocation, DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK); 69 target.setTransfer(new Transfer[] {URLTransfer.getInstance(), FileTransfer.getInstance()}); 70 target.addDropListener(new TextURLDropAdapter(fLocation, true)); 71 fLocation.addModifyListener(e -> validate()); 72 73 if (fEdit != null) { 74 if (fEdit.getURL() != null) { 75 fLocation.setText(fEdit.getURL()); 76 } 77 } else { 78 String initialText = "http://"; //$NON-NLS-1$ 79 fLocation.setText(initialText); 80 fLocation.setSelection(initialText.length()); 81 } 82 83 validate(); 84 85 return comp; 86 } 87 validate()88 protected void validate() { 89 String location = fLocation.getText().trim(); 90 if (location.length() == 0) { 91 updateStatus(new Status(IStatus.ERROR, IPDEUIConstants.PLUGIN_ID, PDEUIMessages.UpdatesSection_ErrorLocationNoName)); 92 return; 93 } 94 try { 95 new URL(location); 96 } catch (MalformedURLException e) { 97 updateStatus(new Status(IStatus.ERROR, IPDEUIConstants.PLUGIN_ID, PDEUIMessages.UpdatesSection_ErrorInvalidURL)); 98 return; 99 } 100 updateStatus(Status.OK_STATUS); 101 } 102 103 @Override okPressed()104 protected void okPressed() { 105 if (fEdit != null) { 106 // Remove the repository and add a new one 107 getProduct().removeRepositories(new IRepositoryInfo[] {fEdit}); 108 } 109 110 IProductModelFactory factory = getModel().getFactory(); 111 fEdit = factory.createRepositoryInfo(); 112 String location = fLocation.getText().trim(); 113 if (!location.startsWith("http://") && !location.startsWith("file:")) //$NON-NLS-1$ //$NON-NLS-2$ 114 location = "http://" + location; //$NON-NLS-1$ 115 fEdit.setURL(location); 116 fEdit.setEnabled(true); 117 getProduct().addRepositories(new IRepositoryInfo[] {fEdit}); 118 super.okPressed(); 119 } 120 121 @Override createHelpControl(Composite parent)122 protected Control createHelpControl(Composite parent) { 123 return parent; 124 } 125 126 /** 127 * @return a repository info containing the values set in the dialog or <code>null</code> 128 */ getResult()129 public IRepositoryInfo getResult() { 130 return fEdit; 131 } 132 133 } 134 135 136 private class ContentProvider implements IStructuredContentProvider { 137 ContentProvider()138 ContentProvider() { 139 } 140 141 @Override getElements(Object inputElement)142 public Object[] getElements(Object inputElement) { 143 if (inputElement instanceof IProduct) { 144 return ((IProduct) inputElement).getRepositories(); 145 } 146 return new Object[0]; 147 } 148 149 150 } 151 152 private class LabelProvider extends PDELabelProvider { 153 @Override getColumnImage(Object obj, int index)154 public Image getColumnImage(Object obj, int index) { 155 if (index == 0) 156 return get(PDEPluginImages.DESC_REPOSITORY_OBJ); 157 return null; 158 } 159 160 @Override getColumnText(Object obj, int index)161 public String getColumnText(Object obj, int index) { 162 IRepositoryInfo repo = (IRepositoryInfo) obj; 163 switch (index) { 164 case 0 : 165 return repo.getURL(); 166 case 1 : 167 return Boolean.toString(repo.getEnabled()); 168 } 169 return null; 170 } 171 172 } 173 174 private TableViewer fRepositoryTable; 175 private TableEditor fEnabledColumnEditor; 176 UpdatesSection(PDEFormPage formPage, Composite parent)177 public UpdatesSection(PDEFormPage formPage, Composite parent) { 178 super(formPage, parent, Section.DESCRIPTION, getButtonLabels()); 179 } 180 getButtonLabels()181 private static String[] getButtonLabels() { 182 String[] labels = new String[4]; 183 labels[0] = PDEUIMessages.UpdatesSection_add; 184 labels[1] = PDEUIMessages.UpdatesSection_edit; 185 labels[2] = PDEUIMessages.UpdatesSection_remove; 186 labels[3] = PDEUIMessages.UpdatesSection_removeAll; 187 return labels; 188 } 189 190 @Override createClient(Section section, FormToolkit toolkit)191 protected void createClient(Section section, FormToolkit toolkit) { 192 193 section.setLayout(FormLayoutFactory.createClearGridLayout(false, 1)); 194 GridData sectionData = new GridData(GridData.FILL_BOTH); 195 sectionData.verticalSpan = 2; 196 section.setLayoutData(sectionData); 197 198 Composite container = createClientContainer(section, 2, toolkit); 199 createViewerPartControl(container, SWT.MULTI | SWT.FULL_SELECTION, 2, toolkit); 200 container.setLayoutData(new GridData(GridData.FILL_BOTH)); 201 202 TablePart tablePart = getTablePart(); 203 fRepositoryTable = tablePart.getTableViewer(); 204 205 final Table table = fRepositoryTable.getTable(); 206 207 final TableColumn locationColumn = new TableColumn(table, SWT.LEFT); 208 locationColumn.setText(PDEUIMessages.UpdatesSection_LocationColumn); 209 locationColumn.setWidth(240); 210 211 final TableColumn enabledColumn = new TableColumn(table, SWT.LEFT); 212 enabledColumn.setText(PDEUIMessages.UpdatesSection_EnabledColumn); 213 enabledColumn.setWidth(120); 214 215 GridData data = (GridData) tablePart.getControl().getLayoutData(); 216 data.minimumWidth = 200; 217 218 tablePart.setButtonEnabled(0, isEditable()); 219 tablePart.setButtonEnabled(1, isEditable()); 220 221 table.setHeaderVisible(true); 222 toolkit.paintBordersFor(container); 223 224 table.addControlListener(new ControlListener() { 225 226 @Override 227 public void controlMoved(ControlEvent e) { 228 } 229 230 @Override 231 public void controlResized(ControlEvent e) { 232 int size = table.getSize().x; 233 locationColumn.setWidth(size / 6 * 5); 234 enabledColumn.setWidth(size / 6 * 1); 235 } 236 237 }); 238 239 240 241 fRepositoryTable.setLabelProvider(new LabelProvider()); 242 fRepositoryTable.setContentProvider(new ContentProvider()); 243 fRepositoryTable.setComparator(new ViewerComparator() { 244 @Override 245 public int compare(Viewer viewer, Object e1, Object e2) { 246 IRepositoryInfo r1 = (IRepositoryInfo) e1; 247 IRepositoryInfo r2 = (IRepositoryInfo) e2; 248 return super.compare(viewer, r1.getURL(), r2.getURL()); 249 } 250 }); 251 fRepositoryTable.setInput(getProduct()); 252 createEditors(); 253 254 section.setClient(container); 255 256 section.setText(PDEUIMessages.UpdatesSection_title); 257 section.setDescription(PDEUIMessages.UpdatesSection_description); 258 } 259 260 261 @Override buttonSelected(int index)262 protected void buttonSelected(int index) { 263 switch (index) { 264 case 0 : 265 handleAdd(); 266 break; 267 case 1 : 268 handleEdit(fRepositoryTable.getStructuredSelection()); 269 break; 270 case 2 : 271 handleDelete(); 272 break; 273 case 3 : 274 handleRemoveAll(); 275 break; 276 } 277 } 278 279 280 @Override handleDoubleClick(IStructuredSelection selection)281 protected void handleDoubleClick(IStructuredSelection selection) { 282 handleEdit(selection); 283 } 284 285 @Override doGlobalAction(String actionId)286 public boolean doGlobalAction(String actionId) { 287 if (actionId.equals(ActionFactory.DELETE.getId())) { 288 handleDelete(); 289 return true; 290 } 291 if (actionId.equals(ActionFactory.CUT.getId())) { 292 handleDelete(); 293 return false; 294 } 295 return super.doGlobalAction(actionId); 296 } 297 298 handleEdit(IStructuredSelection selection)299 private void handleEdit(IStructuredSelection selection) { 300 clearEditors(); 301 if (!selection.isEmpty()) { 302 Object[] objects = selection.toArray(); 303 RepositoryDialog dialog = new RepositoryDialog(PDEPlugin.getActiveWorkbenchShell(), (IRepositoryInfo) objects[0]); 304 if (dialog.open() == Window.OK) { 305 IRepositoryInfo result = dialog.getResult(); 306 if (result != null) { 307 fRepositoryTable.refresh(); 308 fRepositoryTable.setSelection(new StructuredSelection(result)); 309 updateButtons(); 310 } 311 } 312 } 313 } 314 handleDelete()315 private void handleDelete() { 316 clearEditors(); 317 IStructuredSelection ssel = fRepositoryTable.getStructuredSelection(); 318 if (!ssel.isEmpty()) { 319 Object[] objects = ssel.toArray(); 320 IRepositoryInfo[] repos = new IRepositoryInfo[objects.length]; 321 System.arraycopy(objects, 0, repos, 0, objects.length); 322 getProduct().removeRepositories(repos); 323 fRepositoryTable.refresh(false); 324 updateButtons(); 325 } 326 } 327 handleRemoveAll()328 private void handleRemoveAll() { 329 clearEditors(); 330 getProduct().removeRepositories(getProduct().getRepositories()); 331 fRepositoryTable.refresh(false); 332 updateButtons(); 333 } 334 handleAdd()335 private void handleAdd() { 336 clearEditors(); 337 RepositoryDialog dialog = new RepositoryDialog(PDEPlugin.getActiveWorkbenchShell(), null); 338 if (dialog.open() == Window.OK) { 339 IRepositoryInfo result = dialog.getResult(); 340 if (result != null) { 341 fRepositoryTable.refresh(); 342 fRepositoryTable.setSelection(new StructuredSelection(result)); 343 updateButtons(); 344 } 345 } 346 } 347 getProduct()348 private IProduct getProduct() { 349 return getModel().getProduct(); 350 } 351 getModel()352 private IProductModel getModel() { 353 return (IProductModel) getPage().getPDEEditor().getAggregateModel(); 354 } 355 356 @Override refresh()357 public void refresh() { 358 fRepositoryTable.refresh(); 359 updateButtons(); 360 super.refresh(); 361 } 362 363 364 @Override selectionChanged(IStructuredSelection selection)365 protected void selectionChanged(IStructuredSelection selection) { 366 getPage().getPDEEditor().setSelection(selection); 367 updateButtons(); 368 } 369 370 @Override setFormInput(Object input)371 public boolean setFormInput(Object input) { 372 if (input instanceof IProductPlugin) { 373 fRepositoryTable.setSelection(new StructuredSelection(input), true); 374 return true; 375 } 376 return super.setFormInput(input); 377 } 378 379 @Override modelChanged(IModelChangedEvent e)380 public void modelChanged(IModelChangedEvent e) { 381 // No need to call super, handling world changed event here 382 fRepositoryTable.setInput(getProduct()); 383 fRepositoryTable.refresh(); 384 updateButtons(); 385 clearEditors(); 386 } 387 updateButtons()388 private void updateButtons() { 389 TablePart tablePart = getTablePart(); 390 ISelection selection = getViewerSelection(); 391 boolean enabled = isEditable() && !selection.isEmpty() && selection instanceof IStructuredSelection && ((IStructuredSelection) selection).getFirstElement() instanceof IRepositoryInfo; 392 tablePart.setButtonEnabled(1, enabled); 393 tablePart.setButtonEnabled(2, enabled); 394 tablePart.setButtonEnabled(3, isEditable() && getProduct().getRepositories().length > 0); 395 } 396 clearEditors()397 private void clearEditors() { 398 Control oldEditor = fEnabledColumnEditor.getEditor(); 399 if (oldEditor != null && !oldEditor.isDisposed()) 400 oldEditor.dispose(); 401 402 } 403 createEditors()404 private void createEditors() { 405 final Table table = fRepositoryTable.getTable(); 406 407 fEnabledColumnEditor = new TableEditor(table); 408 fEnabledColumnEditor.horizontalAlignment = SWT.CENTER; 409 fEnabledColumnEditor.grabHorizontal = true; 410 fEnabledColumnEditor.minimumWidth = 50; 411 412 table.addSelectionListener(widgetSelectedAdapter(e -> showControls())); 413 } 414 showControls()415 private void showControls() { 416 // Clean up any previous editor control 417 clearEditors(); 418 419 // Identify the selected row 420 Table table = fRepositoryTable.getTable(); 421 IStructuredSelection selection = fRepositoryTable.getStructuredSelection(); 422 if (selection.isEmpty()) 423 return; 424 final TableItem item = table.getSelection()[0]; 425 if (item != null && !isEditable()) 426 return; 427 428 if (item != null) { 429 final IRepositoryInfo repo = (IRepositoryInfo) selection.getFirstElement(); 430 final CCombo combo = new CCombo(table, SWT.BORDER | SWT.READ_ONLY); 431 combo.setItems(new String[] {Boolean.toString(true), Boolean.toString(false)}); 432 combo.setText(item.getText(1)); 433 combo.pack(); 434 combo.addSelectionListener(widgetSelectedAdapter(e -> { 435 item.setText(1, combo.getText()); 436 repo.setEnabled(Boolean.parseBoolean(combo.getText())); 437 })); 438 fEnabledColumnEditor.setEditor(combo, item, 1); 439 } 440 } 441 } 442