1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
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 package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
17 
18 import static com.android.SdkConstants.ANDROID_LAYOUT_RESOURCE_PREFIX;
19 import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutMetadata.KEY_LV_FOOTER;
20 import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutMetadata.KEY_LV_HEADER;
21 import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutMetadata.KEY_LV_ITEM;
22 
23 import com.android.annotations.NonNull;
24 import com.android.annotations.Nullable;
25 import com.android.ide.common.rendering.api.Capability;
26 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
27 import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
28 import com.android.ide.eclipse.adt.internal.resources.CyclicDependencyValidator;
29 import com.android.ide.eclipse.adt.internal.ui.ResourceChooser;
30 import com.android.resources.ResourceType;
31 
32 import org.eclipse.core.resources.IFile;
33 import org.eclipse.jface.action.Action;
34 import org.eclipse.jface.action.ActionContributionItem;
35 import org.eclipse.jface.action.IAction;
36 import org.eclipse.jface.action.Separator;
37 import org.eclipse.jface.window.Window;
38 import org.eclipse.swt.widgets.Menu;
39 import org.w3c.dom.Node;
40 
41 /**
42  * "Preview List Content" context menu which lists available data types and layouts
43  * the user can choose to view the ListView as.
44  */
45 public class ListViewTypeMenu extends SubmenuAction {
46     /** Associated canvas */
47     private final LayoutCanvas mCanvas;
48     /** When true, this menu is for a grid rather than a simple list */
49     private boolean mGrid;
50     /** When true, this menu is for a spinner rather than a simple list */
51     private boolean mSpinner;
52 
53     /**
54      * Creates a "Preview List Content" menu
55      *
56      * @param canvas associated canvas
57      * @param isGrid whether the menu is for a grid rather than a list
58      * @param isSpinner whether the menu is for a spinner rather than a list
59      */
ListViewTypeMenu(LayoutCanvas canvas, boolean isGrid, boolean isSpinner)60     public ListViewTypeMenu(LayoutCanvas canvas, boolean isGrid, boolean isSpinner) {
61         super(isGrid ? "Preview Grid Content" : isSpinner ? "Preview Spinner Layout"
62                 : "Preview List Content");
63         mCanvas = canvas;
64         mGrid = isGrid;
65         mSpinner = isSpinner;
66     }
67 
68     @Override
addMenuItems(Menu menu)69     protected void addMenuItems(Menu menu) {
70         GraphicalEditorPart graphicalEditor = mCanvas.getEditorDelegate().getGraphicalEditor();
71         if (graphicalEditor.renderingSupports(Capability.ADAPTER_BINDING)) {
72             IAction action = new PickLayoutAction("Choose Layout...", KEY_LV_ITEM);
73             new ActionContributionItem(action).fill(menu, -1);
74             new Separator().fill(menu, -1);
75 
76             String selected = getSelectedLayout();
77             if (selected != null) {
78                 if (selected.startsWith(ANDROID_LAYOUT_RESOURCE_PREFIX)) {
79                     selected = selected.substring(ANDROID_LAYOUT_RESOURCE_PREFIX.length());
80                 }
81             }
82 
83             if (mSpinner) {
84                 action = new SetListTypeAction("Spinner Item",
85                         "simple_spinner_item", selected); //$NON-NLS-1$
86                 new ActionContributionItem(action).fill(menu, -1);
87                 action = new SetListTypeAction("Spinner Dropdown Item",
88                         "simple_spinner_dropdown_item", selected); //$NON-NLS-1$
89                 new ActionContributionItem(action).fill(menu, -1);
90                 return;
91             }
92 
93             action = new SetListTypeAction("Simple List Item",
94                     "simple_list_item_1", selected); //$NON-NLS-1$
95             new ActionContributionItem(action).fill(menu, -1);
96             action = new SetListTypeAction("Simple 2-Line List Item",
97                     "simple_list_item_2", //$NON-NLS-1$
98                     selected);
99             new ActionContributionItem(action).fill(menu, -1);
100             action = new SetListTypeAction("Checked List Item",
101                     "simple_list_item_checked", //$NON-NLS-1$
102                     selected);
103             new ActionContributionItem(action).fill(menu, -1);
104             action = new SetListTypeAction("Single Choice List Item",
105                     "simple_list_item_single_choice", //$NON-NLS-1$
106                     selected);
107             new ActionContributionItem(action).fill(menu, -1);
108             action = new SetListTypeAction("Multiple Choice List Item",
109                     "simple_list_item_multiple_choice", //$NON-NLS-1$
110                     selected);
111             if (!mGrid) {
112                 new Separator().fill(menu, -1);
113                 action = new SetListTypeAction("Simple Expandable List Item",
114                         "simple_expandable_list_item_1", selected); //$NON-NLS-1$
115                 new ActionContributionItem(action).fill(menu, -1);
116                 action = new SetListTypeAction("Simple 2-Line Expandable List Item",
117                         "simple_expandable_list_item_2", //$NON-NLS-1$
118                         selected);
119                 new ActionContributionItem(action).fill(menu, -1);
120 
121                 new Separator().fill(menu, -1);
122                 action = new PickLayoutAction("Choose Header...", KEY_LV_HEADER);
123                 new ActionContributionItem(action).fill(menu, -1);
124                 action = new PickLayoutAction("Choose Footer...", KEY_LV_FOOTER);
125                 new ActionContributionItem(action).fill(menu, -1);
126             }
127         } else {
128             // Should we just hide the menu item instead?
129             addDisabledMessageItem(
130                     "Not supported for this SDK version; try changing the Render Target");
131         }
132     }
133 
134     private class SetListTypeAction extends Action {
135         private final String mLayout;
136 
SetListTypeAction(String title, String layout, String selected)137         public SetListTypeAction(String title, String layout, String selected) {
138             super(title, IAction.AS_RADIO_BUTTON);
139             mLayout = layout;
140 
141             if (layout.equals(selected)) {
142                 setChecked(true);
143             }
144         }
145 
146         @Override
run()147         public void run() {
148             if (isChecked()) {
149                 setNewType(KEY_LV_ITEM, ANDROID_LAYOUT_RESOURCE_PREFIX + mLayout);
150             }
151         }
152     }
153 
154     /**
155      * Action which brings up a resource chooser to choose an arbitrary layout as the
156      * layout to be previewed in the list.
157      */
158     private class PickLayoutAction extends Action {
159         private final String mType;
160 
PickLayoutAction(String title, String type)161         public PickLayoutAction(String title, String type) {
162             super(title, IAction.AS_PUSH_BUTTON);
163             mType = type;
164         }
165 
166         @Override
run()167         public void run() {
168             LayoutEditorDelegate delegate = mCanvas.getEditorDelegate();
169             IFile file = delegate.getEditor().getInputFile();
170             GraphicalEditorPart editor = delegate.getGraphicalEditor();
171             ResourceChooser dlg = ResourceChooser.create(editor, ResourceType.LAYOUT)
172                 .setInputValidator(CyclicDependencyValidator.create(file))
173                 .setInitialSize(85, 10)
174                 .setCurrentResource(getSelectedLayout());
175             int result = dlg.open();
176             if (result == ResourceChooser.CLEAR_RETURN_CODE) {
177                 setNewType(mType, null);
178             } else if (result == Window.OK) {
179                 String newType = dlg.getCurrentResource();
180                 setNewType(mType, newType);
181             }
182         }
183     }
184 
185     @Nullable
getSelectedLayout()186     private String getSelectedLayout() {
187         String layout = null;
188         SelectionManager selectionManager = mCanvas.getSelectionManager();
189         for (SelectionItem item : selectionManager.getSelections()) {
190             UiViewElementNode node = item.getViewInfo().getUiViewNode();
191             if (node != null) {
192                 Node xmlNode = node.getXmlNode();
193                 layout = LayoutMetadata.getProperty(xmlNode, KEY_LV_ITEM);
194                 if (layout != null) {
195                     return layout;
196                 }
197             }
198         }
199 
200         return null;
201     }
202 
setNewType(@onNull String type, @Nullable String layout)203     private void setNewType(@NonNull String type, @Nullable String layout) {
204         LayoutEditorDelegate delegate = mCanvas.getEditorDelegate();
205         GraphicalEditorPart graphicalEditor = delegate.getGraphicalEditor();
206         SelectionManager selectionManager = mCanvas.getSelectionManager();
207 
208         for (SelectionItem item : selectionManager.getSnapshot()) {
209             UiViewElementNode node = item.getViewInfo().getUiViewNode();
210             if (node != null) {
211                 Node xmlNode = node.getXmlNode();
212                 LayoutMetadata.setProperty(delegate.getEditor(), xmlNode, type, layout);
213             }
214         }
215 
216         // Refresh
217         graphicalEditor.recomputeLayout();
218         mCanvas.redraw();
219     }
220 }
221