View Javadoc

1   /**
2    * This file Copyright (c) 2011-2014 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.ui.workbench.tree;
35  
36  import info.magnolia.ui.workbench.event.ItemEditedEvent;
37  import info.magnolia.ui.workbench.list.ListViewImpl;
38  
39  import java.util.List;
40  
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  
44  import com.vaadin.event.Action;
45  import com.vaadin.event.Action.Container;
46  import com.vaadin.event.Action.Handler;
47  import com.vaadin.event.ShortcutAction;
48  import com.vaadin.event.dd.DropHandler;
49  import com.vaadin.ui.Field;
50  import com.vaadin.ui.Table.TableDragMode;
51  import com.vaadin.ui.TreeTable;
52  
53  /**
54   * Vaadin UI component that displays a tree.
55   */
56  public class TreeViewImpl extends ListViewImpl implements TreeView {
57  
58      private static final Logger log = LoggerFactory.getLogger(TreeViewImpl.class);
59  
60      private final TreeTable treeTable;
61  
62      private Container shortcutActionManager;
63  
64      private Handler editingKeyboardHandler;
65  
66      private TreeRowScroller rowScroller;
67  
68      private final ItemEditedEvent.Handler itemEditedListener = new ItemEditedEvent.Handler() {
69  
70          @Override
71          public void onItemEdited(ItemEditedEvent event) {
72              if (getListener() != null) {
73                  getListener().onItemEdited(event.getItem());
74              }
75          }
76      };
77  
78      public TreeViewImpl() {
79          this(new InplaceEditingTreeTable());
80      }
81  
82      public TreeViewImpl(TreeTable tree) {
83          super(tree);
84          tree.setSortEnabled(false);
85  
86          tree.setCollapsed(tree.firstItemId(), false);
87          rowScroller = new TreeRowScroller(tree);
88          this.treeTable = tree;
89      }
90  
91      @Override
92      public void setActionManager(Container shortcutActionManager) {
93          this.shortcutActionManager = shortcutActionManager;
94          bindKeyboardShortcuts();
95      }
96  
97      @Override
98      public void setEditable(boolean editable) {
99          treeTable.setEditable(editable);
100         bindKeyboardShortcuts();
101     }
102 
103     private void bindKeyboardShortcuts() {
104         if (treeTable.isEditable() && treeTable instanceof InplaceEditingTreeTable) {
105             ((InplaceEditingTreeTable) treeTable).addItemEditedListener(itemEditedListener);
106             if (shortcutActionManager != null) {
107                 if (editingKeyboardHandler == null) {
108                     editingKeyboardHandler = new EditingKeyboardHandler((InplaceEditingTreeTable) treeTable);
109                 }
110                 shortcutActionManager.addActionHandler(editingKeyboardHandler);
111             }
112         } else {
113             ((InplaceEditingTreeTable) treeTable).removeItemEditedListener(itemEditedListener);
114             if (shortcutActionManager != null) {
115                 shortcutActionManager.removeActionHandler(editingKeyboardHandler);
116             }
117         }
118     }
119 
120     @Override
121     public void setEditableColumns(Object... propertyIds) {
122         ((InplaceEditingTreeTable) treeTable).setEditableColumns(propertyIds);
123     }
124 
125     @Override
126     public void setDragAndDropHandler(DropHandler dropHandler) {
127         if (dropHandler != null) {
128             treeTable.setDragMode(TableDragMode.ROW);
129             treeTable.setDropHandler(dropHandler);
130         } else {
131             treeTable.setDragMode(TableDragMode.NONE);
132             treeTable.setDropHandler(null);
133         }
134     }
135 
136     @Override
137     public void select(List<String> itemIds) {
138         String firstItemId = itemIds == null || itemIds.isEmpty() ? null : itemIds.get(0);
139         if (firstItemId == null) {
140             return;
141         }
142 
143         treeTable.setValue(null);
144         for (String id : itemIds) {
145             treeTable.select(id);
146         }
147         rowScroller.bringRowIntoView(firstItemId);
148     }
149 
150     @Override
151     public void expand(String itemId) {
152         rowScroller.expandTreeToNode(itemId, true);
153     }
154 
155     @Override
156     protected TreeView.Listener getListener() {
157         return (TreeView.Listener) super.getListener();
158     }
159 
160     @Override
161     public TreeTable asVaadinComponent() {
162         return treeTable;
163     }
164 
165     // KEYBOARD SHORTCUTS
166 
167     /**
168      * The Class EditingKeyboardHandler for keyboard shortcuts with inplace editing.
169      */
170     private class EditingKeyboardHandler implements Handler {
171 
172         private final ShortcutAction enter = new ShortcutAction("Enter", ShortcutAction.KeyCode.ENTER, null);
173 
174         private final ShortcutAction tabNext = new ShortcutAction("Tab", ShortcutAction.KeyCode.TAB, null);
175 
176         private final ShortcutAction tabPrev = new ShortcutAction("Shift+Tab", ShortcutAction.KeyCode.TAB, new int[] { ShortcutAction.ModifierKey.SHIFT });
177 
178         private final ShortcutAction escape = new ShortcutAction("Esc", ShortcutAction.KeyCode.ESCAPE, null);
179 
180         private final InplaceEditingTreeTable tree;
181 
182         public EditingKeyboardHandler(InplaceEditingTreeTable tree) {
183             this.tree = tree;
184         }
185 
186         @Override
187         public Action[] getActions(Object target, Object sender) {
188             // TODO: Find a better solution for handling tab key events: MGNLUI-1384
189             return new Action[] { enter, tabNext, tabPrev, escape };
190         }
191 
192         @Override
193         public void handleAction(Action action, Object sender, Object target) {
194             /*
195              * In case of enter the Action needs to be casted back to
196              * ShortcutAction because for some reason the object is not same
197              * as this.enter object. In that case keycode is used in comparison.
198              */
199             if (!(action instanceof ShortcutAction)) {
200                 return;
201             }
202             ShortcutAction shortcut = (ShortcutAction) action;
203 
204             if (target != tree && target instanceof Field) {
205                 Field<?> field = (Field<?>) target;
206 
207                 if (shortcut == enter || shortcut.getKeyCode() == enter.getKeyCode()) {
208                     tree.fireItemEditedEvent(field.getPropertyDataSource());
209                     tree.setEditing(null, null);
210 
211                 } else if (action == tabNext) {
212                     tree.editNextCell(field);
213 
214                 } else if (action == tabPrev) {
215                     tree.editPreviousCell(field);
216 
217                 } else if (action == escape) {
218                     tree.setEditing(null, null);
219                 }
220             } else if (target == treeTable) {
221                 if (tree.getValue() == null) {
222                     return;
223                 }
224 
225                 if (shortcut == enter || shortcut.getKeyCode() == enter.getKeyCode()) {
226                     tree.editFirstCellofFirstSelectedRow();
227 
228                 }
229             }
230         }
231     }
232 
233 }