1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.sdkuilib.internal.repository; 18 19 import com.android.sdklib.internal.repository.Archive; 20 import com.android.sdklib.internal.repository.IDescription; 21 import com.android.sdklib.internal.repository.Package; 22 import com.android.sdkuilib.repository.UpdaterWindow.ISdkListener; 23 24 import org.eclipse.jface.dialogs.MessageDialog; 25 import org.eclipse.jface.viewers.ISelection; 26 import org.eclipse.jface.viewers.IStructuredSelection; 27 import org.eclipse.jface.viewers.TableViewer; 28 import org.eclipse.swt.SWT; 29 import org.eclipse.swt.events.ControlAdapter; 30 import org.eclipse.swt.events.ControlEvent; 31 import org.eclipse.swt.events.SelectionAdapter; 32 import org.eclipse.swt.events.SelectionEvent; 33 import org.eclipse.swt.graphics.Rectangle; 34 import org.eclipse.swt.layout.GridData; 35 import org.eclipse.swt.layout.GridLayout; 36 import org.eclipse.swt.widgets.Button; 37 import org.eclipse.swt.widgets.Composite; 38 import org.eclipse.swt.widgets.Group; 39 import org.eclipse.swt.widgets.Label; 40 import org.eclipse.swt.widgets.Table; 41 import org.eclipse.swt.widgets.TableColumn; 42 import org.eclipse.swt.widgets.Text; 43 44 import java.io.File; 45 46 /* 47 * TODO list 48 * - select => update desc, enable update + delete, enable home page if url 49 * - home page callback 50 * - update callback 51 * - delete callback 52 * - refresh callback 53 */ 54 55 public class LocalPackagesPage extends Composite implements ISdkListener { 56 57 private final UpdaterData mUpdaterData; 58 59 private Label mSdkLocLabel; 60 private Text mSdkLocText; 61 private Button mSdkLocBrowse; 62 private TableViewer mTableViewerPackages; 63 private Table mTablePackages; 64 private TableColumn mColumnPackages; 65 private Group mDescriptionContainer; 66 private Composite mContainerButtons; 67 private Button mUpdateButton; 68 private Label mPlaceholder1; 69 private Button mDeleteButton; 70 private Label mPlaceholder2; 71 private Button mRefreshButton; 72 private Label mDescriptionLabel; 73 74 75 /** 76 * Create the composite. 77 * @param parent The parent of the composite. 78 * @param updaterData An instance of {@link UpdaterData}. 79 */ 80 public LocalPackagesPage(Composite parent, UpdaterData updaterData) { 81 super(parent, SWT.BORDER); 82 83 mUpdaterData = updaterData; 84 85 createContents(this); 86 postCreate(); //$hide$ 87 } 88 89 private void createContents(Composite parent) { 90 parent.setLayout(new GridLayout(3, false)); 91 92 createSdkLocation(parent); 93 94 mTableViewerPackages = new TableViewer(parent, SWT.BORDER | SWT.FULL_SELECTION); 95 mTablePackages = mTableViewerPackages.getTable(); 96 mTablePackages.setHeaderVisible(true); 97 mTablePackages.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); 98 mTablePackages.addSelectionListener(new SelectionAdapter() { 99 @Override 100 public void widgetSelected(SelectionEvent e) { 101 onTreeSelected(); //$hide$ 102 } 103 }); 104 105 mColumnPackages = new TableColumn(mTablePackages, SWT.NONE); 106 mColumnPackages.setWidth(377); 107 mColumnPackages.setText("Installed Packages"); 108 109 mDescriptionContainer = new Group(parent, SWT.NONE); 110 mDescriptionContainer.setLayout(new GridLayout(1, false)); 111 mDescriptionContainer.setText("Description"); 112 mDescriptionContainer.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1)); 113 114 mDescriptionLabel = new Label(mDescriptionContainer, SWT.NONE); 115 mDescriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true, 1, 1)); 116 mDescriptionLabel.setText("Line1\nLine2\nLine3"); 117 118 mContainerButtons = new Composite(parent, SWT.NONE); 119 mContainerButtons.setLayout(new GridLayout(5, false)); 120 mContainerButtons.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1)); 121 122 mUpdateButton = new Button(mContainerButtons, SWT.NONE); 123 mUpdateButton.setText("Update All..."); 124 mUpdateButton.addSelectionListener(new SelectionAdapter() { 125 @Override 126 public void widgetSelected(SelectionEvent e) { 127 onUpdateSelected(); //$hide$ (hide from SWT designer) 128 } 129 }); 130 131 mPlaceholder1 = new Label(mContainerButtons, SWT.NONE); 132 mPlaceholder1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); 133 134 mDeleteButton = new Button(mContainerButtons, SWT.NONE); 135 mDeleteButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1)); 136 mDeleteButton.setText("Delete..."); 137 mDeleteButton.addSelectionListener(new SelectionAdapter() { 138 @Override 139 public void widgetSelected(SelectionEvent e) { 140 onDeleteSelected(); //$hide$ (hide from SWT designer) 141 } 142 }); 143 144 mPlaceholder2 = new Label(mContainerButtons, SWT.NONE); 145 mPlaceholder2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); 146 147 mRefreshButton = new Button(mContainerButtons, SWT.NONE); 148 mRefreshButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 149 mRefreshButton.setText("Refresh"); 150 mRefreshButton.addSelectionListener(new SelectionAdapter() { 151 @Override 152 public void widgetSelected(SelectionEvent e) { 153 onRefreshSelected(); //$hide$ (hide from SWT designer) 154 } 155 }); 156 } 157 158 private void createSdkLocation(Composite parent) { 159 mSdkLocLabel = new Label(parent, SWT.NONE); 160 mSdkLocLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 161 mSdkLocLabel.setText("SDK Location:"); 162 163 // If the sdk path is not user-customizable, do not create 164 // the browse button and use horizSpan=2 on the text field. 165 166 mSdkLocText = new Text(parent, SWT.BORDER); 167 mSdkLocText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 168 169 if (mUpdaterData.canUserChangeSdkRoot()) { 170 mSdkLocBrowse = new Button(parent, SWT.NONE); 171 mSdkLocBrowse.setText("Browse..."); 172 } else { 173 mSdkLocText.setEditable(false); 174 ((GridData)mSdkLocText.getLayoutData()).horizontalSpan++; 175 } 176 177 if (mUpdaterData.getOsSdkRoot() != null) { 178 mSdkLocText.setText(mUpdaterData.getOsSdkRoot()); 179 } 180 } 181 182 @Override 183 public void dispose() { 184 mUpdaterData.removeListener(this); 185 super.dispose(); 186 } 187 188 @Override 189 protected void checkSubclass() { 190 // Disable the check that prevents subclassing of SWT components 191 } 192 193 // -- Start of internal part ---------- 194 // Hide everything down-below from SWT designer 195 //$hide>>$ 196 197 /** 198 * Called by the constructor right after {@link #createContents(Composite)}. 199 */ 200 private void postCreate() { 201 mUpdaterData.addListeners(this); 202 adjustColumnsWidth(); 203 updateButtonsState(); 204 } 205 206 /** 207 * Adds a listener to adjust the columns width when the parent is resized. 208 * <p/> 209 * If we need something more fancy, we might want to use this: 210 * http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet77.java?view=co 211 */ 212 private void adjustColumnsWidth() { 213 // Add a listener to resize the column to the full width of the table 214 ControlAdapter resizer = new ControlAdapter() { 215 @Override 216 public void controlResized(ControlEvent e) { 217 Rectangle r = mTablePackages.getClientArea(); 218 mColumnPackages.setWidth(r.width); 219 } 220 }; 221 mTablePackages.addControlListener(resizer); 222 resizer.controlResized(null); 223 } 224 225 /** 226 * Enable or disable buttons depending on list content and selection 227 */ 228 private void updateButtonsState() { 229 ISelection sel = mTableViewerPackages.getSelection(); 230 boolean hasSelection = sel != null && !sel.isEmpty(); 231 232 mUpdateButton.setEnabled(mTablePackages.getItemCount() > 0); 233 mDeleteButton.setEnabled(hasSelection); 234 mRefreshButton.setEnabled(true); 235 } 236 237 /** 238 * Called when an item in the package table viewer is selected. 239 * If the items is an {@link IDescription} (as it should), this will display its long 240 * description in the description area. Otherwise when the item is not of the expected 241 * type or there is no selection, it empties the description area. 242 */ 243 private void onTreeSelected() { 244 updateButtonsState(); 245 246 ISelection sel = mTableViewerPackages.getSelection(); 247 if (sel instanceof IStructuredSelection) { 248 Object elem = ((IStructuredSelection) sel).getFirstElement(); 249 if (elem instanceof IDescription) { 250 mDescriptionLabel.setText(((IDescription) elem).getLongDescription()); 251 mDescriptionContainer.layout(true); 252 return; 253 } 254 } 255 mDescriptionLabel.setText(""); //$NON-NLS1-$ 256 } 257 258 private void onUpdateSelected() { 259 mUpdaterData.updateOrInstallAll_WithGUI(null /*selectedArchives*/); 260 } 261 262 private void onDeleteSelected() { 263 ISelection sel = mTableViewerPackages.getSelection(); 264 if (sel instanceof IStructuredSelection) { 265 Object elem = ((IStructuredSelection) sel).getFirstElement(); 266 if (elem instanceof Package) { 267 268 String title = "Delete SDK Package"; 269 String error = null; 270 271 Package p = (Package) elem; 272 Archive[] archives = p.getArchives(); 273 if (archives.length == 1 && archives[0] != null && archives[0].isLocal()) { 274 Archive archive = archives[0]; 275 String osPath = archive.getLocalOsPath(); 276 277 File dir = new File(osPath); 278 if (dir.isDirectory()) { 279 String msg = String.format("Are you sure you want to delete '%1$s' at '%2$s'? This cannot be undone.", 280 p.getShortDescription(), osPath); 281 282 if (MessageDialog.openQuestion(getShell(), title, msg)) { 283 archive.deleteLocal(); 284 285 // refresh list 286 onRefreshSelected(); 287 } 288 } else { 289 error = "Directory not found for this package"; 290 } 291 } else { 292 error = "No local archive found for this package"; 293 } 294 295 if (error != null) { 296 MessageDialog.openError(getShell(), title, error); 297 } 298 299 return; 300 } 301 } 302 } 303 304 private void onRefreshSelected() { 305 mUpdaterData.reloadSdk(); 306 updateButtonsState(); 307 } 308 309 public void onSdkChange(boolean init) { 310 LocalSdkAdapter localSdkAdapter = mUpdaterData.getLocalSdkAdapter(); 311 mTableViewerPackages.setLabelProvider( localSdkAdapter.getLabelProvider()); 312 mTableViewerPackages.setContentProvider(localSdkAdapter.getContentProvider()); 313 mTableViewerPackages.setInput(localSdkAdapter); 314 onTreeSelected(); 315 } 316 317 // End of hiding from SWT Designer 318 //$hide<<$ 319 } 320