OSDN Git Service

Merge change 6506
[android-x86/development.git] / tools / sdkmanager / libs / sdkuilib / src / com / android / sdkuilib / internal / repository / RepoSourcesAdapter.java
1 /*\r
2  * Copyright (C) 2009 The Android Open Source Project\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 package com.android.sdkuilib.internal.repository;\r
18 \r
19 import com.android.sdklib.internal.repository.Archive;\r
20 import com.android.sdklib.internal.repository.IDescription;\r
21 import com.android.sdklib.internal.repository.ITask;\r
22 import com.android.sdklib.internal.repository.ITaskMonitor;\r
23 import com.android.sdklib.internal.repository.Package;\r
24 import com.android.sdklib.internal.repository.RepoSource;\r
25 import com.android.sdklib.internal.repository.Package.UpdateInfo;\r
26 import com.android.sdkuilib.internal.repository.icons.ImageFactory;\r
27 \r
28 import org.eclipse.jface.viewers.IContentProvider;\r
29 import org.eclipse.jface.viewers.ILabelProvider;\r
30 import org.eclipse.jface.viewers.ITreeContentProvider;\r
31 import org.eclipse.jface.viewers.LabelProvider;\r
32 import org.eclipse.jface.viewers.Viewer;\r
33 import org.eclipse.swt.graphics.Image;\r
34 \r
35 import java.util.ArrayList;\r
36 \r
37 /**\r
38  * A list of sdk-repository sources.\r
39  *\r
40  * This implementation is UI dependent.\r
41  */\r
42 public class RepoSourcesAdapter {\r
43 \r
44     private final UpdaterData mUpdaterData;\r
45 \r
46     public static class RepoSourceError implements IDescription {\r
47 \r
48         private final RepoSource mSource;\r
49 \r
50         public RepoSourceError(RepoSource source) {\r
51             mSource = source;\r
52         }\r
53 \r
54         public String getLongDescription() {\r
55             return mSource.getLongDescription();\r
56         }\r
57 \r
58         public String getShortDescription() {\r
59             return mSource.getFetchError();\r
60         }\r
61     }\r
62 \r
63 \r
64     public RepoSourcesAdapter(UpdaterData updaterData) {\r
65         mUpdaterData = updaterData;\r
66     }\r
67 \r
68     public ILabelProvider getLabelProvider() {\r
69         return new ViewerLabelProvider();\r
70     }\r
71 \r
72 \r
73     public IContentProvider getContentProvider() {\r
74         return new TreeContentProvider();\r
75     }\r
76 \r
77     // ------------\r
78 \r
79     private class ViewerLabelProvider extends LabelProvider {\r
80 \r
81         /** Returns an image appropriate for this element. */\r
82         @Override\r
83         public Image getImage(Object element) {\r
84 \r
85             ImageFactory imgFactory = mUpdaterData.getImageFactory();\r
86 \r
87             if (imgFactory != null) {\r
88                 return imgFactory.getImageForObject(element);\r
89             }\r
90 \r
91             return super.getImage(element);\r
92         }\r
93 \r
94         /** Returns the toString of the element. */\r
95         @Override\r
96         public String getText(Object element) {\r
97             if (element instanceof IDescription) {\r
98                 return ((IDescription) element).getShortDescription();\r
99             }\r
100             return super.getText(element);\r
101         }\r
102     }\r
103 \r
104     // ------------\r
105 \r
106     private class TreeContentProvider implements ITreeContentProvider {\r
107 \r
108         // Called when the viewer is disposed\r
109         public void dispose() {\r
110             // pass\r
111         }\r
112 \r
113         // Called when the input is set or changed on the provider\r
114         public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
115             assert newInput == RepoSourcesAdapter.this;\r
116         }\r
117 \r
118         /**\r
119          * Called to collect the root elements for the given input.\r
120          * The input here is a {@link RepoSourcesAdapter} object, this returns an array\r
121          * of {@link RepoSource}.\r
122          */\r
123         public Object[] getElements(Object inputElement) {\r
124             return getChildren(inputElement);\r
125         }\r
126 \r
127         /**\r
128          * Get the children of the given parent. This is requested on-demand as\r
129          * nodes are expanded.\r
130          *\r
131          * For a {@link RepoSourcesAdapter} object, returns an array of {@link RepoSource}s.\r
132          * For a {@link RepoSource}, returns an array of {@link Package}s.\r
133          * For a {@link Package}, returns an array of {@link Archive}s.\r
134          */\r
135         public Object[] getChildren(Object parentElement) {\r
136             if (parentElement == RepoSourcesAdapter.this) {\r
137                 return mUpdaterData.getSources().getSources();\r
138 \r
139             } else if (parentElement instanceof RepoSource) {\r
140                 final RepoSource source = (RepoSource) parentElement;\r
141                 Package[] packages = source.getPackages();\r
142 \r
143                 if (packages == null && source.getFetchError() == null) {\r
144                     final boolean forceHttp = mUpdaterData.getSettingsController().getForceHttp();\r
145 \r
146                     mUpdaterData.getTaskFactory().start("Loading Source", new ITask() {\r
147                         public void run(ITaskMonitor monitor) {\r
148                             source.load(monitor, forceHttp);\r
149                         }\r
150                     });\r
151 \r
152                     packages = source.getPackages();\r
153                 }\r
154                 if (packages != null) {\r
155                     // filter out only the packages that are new/upgrade.\r
156                     if (mUpdaterData.getSettingsController().getShowUpdateOnly()) {\r
157                         return filteredPackages(packages);\r
158                     }\r
159                     return packages;\r
160                 } else if (source.getFetchError() != null) {\r
161                     // Return a dummy entry to display the fetch error\r
162                     return new Object[] { new RepoSourceError(source) };\r
163                 }\r
164 \r
165             } else if (parentElement instanceof Package) {\r
166                 Archive[] archives = ((Package) parentElement).getArchives();\r
167                 if (mUpdaterData.getSettingsController().getShowUpdateOnly()) {\r
168                     for (Archive archive : archives) {\r
169                         // if we only want the compatible archives, then we just take the first\r
170                         // one. it's unlikely there are 2 compatible archives for the same\r
171                         // package\r
172                         if (archive.isCompatible()) {\r
173                             return new Object[] { archive };\r
174                         }\r
175                     }\r
176                 }\r
177 \r
178                 return archives;\r
179             }\r
180 \r
181             return new Object[0];\r
182         }\r
183 \r
184         /**\r
185          * Returns the parent of a given element.\r
186          * The input {@link RepoSourcesAdapter} is the parent of all {@link RepoSource} elements.\r
187          */\r
188         public Object getParent(Object element) {\r
189 \r
190             if (element instanceof RepoSource) {\r
191                 return RepoSourcesAdapter.this;\r
192 \r
193             } else if (element instanceof Package) {\r
194                 return ((Package) element).getParentSource();\r
195             }\r
196             return null;\r
197         }\r
198 \r
199         /**\r
200          * Returns true if a given element has children, which is used to display a\r
201          * "+/expand" box next to the tree node.\r
202          * All {@link RepoSource} and {@link Package} are expandable, whether they actually\r
203          * have any children or not.\r
204          */\r
205         public boolean hasChildren(Object element) {\r
206             return element instanceof RepoSource || element instanceof Package;\r
207         }\r
208     }\r
209 \r
210     /**\r
211      * Filters out a list of remote packages to only keep the ones that are either new or\r
212      * updates of existing package.\r
213      * @param remotePackages the list of packages to filter.\r
214      * @return a non null (but maybe empty) list of new or update packages.\r
215      */\r
216     private Object[] filteredPackages(Package[] remotePackages) {\r
217         // get the installed packages\r
218         Package[] installedPackages = mUpdaterData.getInstalledPackage();\r
219 \r
220         ArrayList<Package> filteredList = new ArrayList<Package>();\r
221 \r
222         // for each remote packages, we look for an existing version.\r
223         // If no existing version -> add to the list\r
224         // if existing version but with older revision -> add it to the list\r
225         for (Package remotePkg : remotePackages) {\r
226             boolean newPkg = true;\r
227 \r
228             // For all potential packages, we also make sure that there's an archive for the current\r
229             // platform, or we simply skip them.\r
230             if (remotePkg.hasCompatibleArchive()) {\r
231                 for (Package installedPkg : installedPackages) {\r
232                     UpdateInfo info = installedPkg.canBeUpdatedBy(remotePkg);\r
233                     if (info == UpdateInfo.UPDATE) {\r
234                         filteredList.add(remotePkg);\r
235                         newPkg = false;\r
236                         break; // there shouldn't be 2 revision of the same package\r
237                     } else if (info != UpdateInfo.INCOMPATIBLE) {\r
238                         newPkg = false;\r
239                         break; // there shouldn't be 2 revision of the same package\r
240                     }\r
241                 }\r
242 \r
243                 // if we have not found the same package, then we add it (it's a new package)\r
244                 if (newPkg) {\r
245                     filteredList.add(remotePkg);\r
246                 }\r
247             }\r
248         }\r
249 \r
250         return filteredList.toArray();\r
251     }\r
252 }\r