View Javadoc
1   /**
2    * This file Copyright (c) 2013-2018 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.admincentral.shellapp.favorites;
35  
36  import info.magnolia.config.registry.DefinitionProvider;
37  import info.magnolia.config.registry.Registry;
38  import info.magnolia.event.EventBus;
39  import info.magnolia.i18nsystem.I18nizer;
40  import info.magnolia.ui.api.app.AppDescriptor;
41  import info.magnolia.ui.api.app.registry.AppDescriptorRegistry;
42  import info.magnolia.ui.api.location.DefaultLocation;
43  import info.magnolia.ui.api.location.Location;
44  import info.magnolia.ui.api.location.LocationController;
45  import info.magnolia.ui.api.shell.Shell;
46  import info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeAdapter;
47  
48  import java.net.URI;
49  import java.net.URISyntaxException;
50  import java.util.List;
51  import java.util.Map;
52  
53  import javax.inject.Inject;
54  
55  import org.apache.commons.lang3.StringUtils;
56  import org.slf4j.Logger;
57  import org.slf4j.LoggerFactory;
58  
59  import com.vaadin.ui.UI;
60  
61  /**
62   * Presenter for Favorites.
63   */
64  public final class FavoritesPresenter implements FavoritesView.Listener {
65  
66      private final static Logger log = LoggerFactory.getLogger(FavoritesPresenter.class);
67  
68      private I18nizer i18nizer;
69      private FavoritesView view;
70      private FavoritesManager favoritesManager;
71      private AppDescriptorRegistry appDescriptorRegistry;
72      private final LocationController locationController;
73      private Shell shell;
74  
75      /**
76       * @deprecated since 5.5.8 - use {@link #FavoritesPresenter(FavoritesView, FavoritesManager, AppDescriptorRegistry, I18nizer, LocationController, Shell)} instead.
77       */
78      @Deprecated
79      public FavoritesPresenter(final FavoritesView view, final FavoritesManager favoritesManager, final AppDescriptorRegistry appDescriptorRegistry, final I18nizer i18nizer,
80                                EventBus adminCentralEventBus, LocationController locationController, Shell shell) {
81          this(view, favoritesManager, appDescriptorRegistry, i18nizer, locationController, shell);
82      }
83  
84      @Inject
85      public FavoritesPresenter(final FavoritesView view, final FavoritesManager favoritesManager, final AppDescriptorRegistry appDescriptorRegistry, final I18nizer i18nizer,
86                                LocationController locationController, Shell shell) {
87          this.view = view;
88          this.favoritesManager = favoritesManager;
89          this.appDescriptorRegistry = appDescriptorRegistry;
90          this.i18nizer = i18nizer;
91          this.locationController = locationController;
92          this.shell = shell;
93      }
94  
95      public FavoritesView start() {
96          view.setListener(this);
97          initializeView();
98          return view;
99      }
100 
101     @Override
102     public void setToInitialState() {
103         // make sure to hide all the icons of the EditableFavoriteItem(s) and to set the to the non-editable-state.
104         for (EditableFavoriteItem item : view.getEditableFavoriteItemList()) {
105             item.setToNonEditableState();
106             item.setIconsVisibility(false);
107         }
108     }
109 
110     @Override
111     public void removeFavorite(String relPath) {
112         favoritesManager.removeFavorite(relPath);
113         initializeView();
114     }
115 
116     @Override
117     public void addFavoriteAndGroup(JcrNewNodeAdapter newFavorite, JcrNewNodeAdapter newGroup) {
118         if (newGroup != null && newGroup.getItemProperty("title") != null && !"".equals(newGroup.getItemProperty("title").getValue())) {
119             favoritesManager.addGroup(newGroup);
120         }
121         favoritesManager.addFavorite(newFavorite);
122         initializeView();
123     }
124 
125     @Override
126     public void addFavorite(JcrNewNodeAdapter favorite) {
127         favoritesManager.addFavorite(favorite);
128         initializeView();
129     }
130 
131     @Override
132     public void moveFavorite(String relPath, String group) {
133         favoritesManager.moveFavorite(relPath, group);
134         initializeView();
135     }
136 
137     @Override
138     public void orderFavoriteBefore(String relPath, String sibling) {
139         favoritesManager.orderFavoriteBefore(relPath, sibling);
140         initializeView();
141     }
142 
143     @Override
144     public void orderFavoriteAfter(String relPath, String sibling) {
145         favoritesManager.orderFavoriteAfter(relPath, sibling);
146         initializeView();
147     }
148 
149     @Override
150     public void orderGroupBefore(String relPath, String sibling) {
151         favoritesManager.orderGroupBefore(relPath, sibling);
152         initializeView();
153     }
154 
155     @Override
156     public void orderGroupAfter(String relPath, String sibling) {
157         favoritesManager.orderGroupAfter(relPath, sibling);
158         initializeView();
159 
160     }
161 
162     @Override
163     public void setItemsEditable(boolean isVisible) {
164         List<EditableFavoriteItem> editableFavoriteItemList = view.getEditableFavoriteItemList();
165         for (EditableFavoriteItem editableFavoriteItem : editableFavoriteItemList) {
166             editableFavoriteItem.setIconsVisibility(isVisible);
167         }
168     }
169 
170     @Override
171     public boolean itemsAreEditable() {
172         List<EditableFavoriteItem> editableFavoriteItemList = view.getEditableFavoriteItemList();
173         return !editableFavoriteItemList.isEmpty() && editableFavoriteItemList.get(0).iconsAreVisible();
174     }
175 
176     @Override
177     public boolean hasItems() {
178         return view.getEditableFavoriteItemList() != null && view.getEditableFavoriteItemList().size() > 0;
179     }
180 
181     @Override
182     public void goToLocation(final String location) {
183         locationController.goTo(new DefaultLocation(location));
184     }
185 
186     public JcrNewNodeAdapter determinePreviousLocation() {
187         JcrNewNodeAdapter favoriteLocation;
188 
189         // at this point the current location in the browser hasn't yet changed to favorite shellapp,
190         // so it is what we need to pre-populate the form for creating a new favorite
191 
192         String previousLocationFragment = shell.getFragment();
193 
194         // skip bookmark resolution if for some reason fragment is empty
195         if (StringUtils.isBlank(previousLocationFragment)) {
196             return createNewFavoriteSuggestion("", "", "");
197         }
198 
199         final String appName = DefaultLocation.extractAppName(previousLocationFragment);
200         final String appType = DefaultLocation.extractAppType(previousLocationFragment);
201         // TODO MGNLUI-1190 should this be added to DefaultLocation as a convenience static method?
202         final String path = StringUtils.substringBetween(previousLocationFragment, ";", ":");
203 
204         // skip bookmark resolution shell apps
205         if (Location.LOCATION_TYPE_SHELL_APP.equals(appType)) {
206             favoriteLocation = createNewFavoriteSuggestion("", "", "");
207         } else {
208             final AppDescriptor appDescriptor;
209 
210             try {
211                 DefinitionProvider<AppDescriptor> definitionProvider = appDescriptorRegistry.getProvider(appName);
212                 appDescriptor = i18nizer.decorate(definitionProvider.get());
213             } catch (Registry.NoSuchDefinitionException | IllegalStateException e) {
214                 throw new RuntimeException(e);
215             }
216 
217             final String appIcon = StringUtils.defaultIfEmpty(appDescriptor.getIcon(), "icon-app");
218             final String title = appDescriptor.getLabel() + " " + (path == null ? "/" : path);
219             favoriteLocation = createNewFavoriteSuggestion(previousLocationFragment, title, appIcon);
220         }
221         return favoriteLocation;
222     }
223 
224     /**
225      * @return a {@link info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeAdapter} used to pre-populate a form in the UI with a suggestion for a new favorite.
226      */
227     public JcrNewNodeAdapter createNewFavoriteSuggestion(String location, String title, String icon) {
228         return favoritesManager.createFavoriteSuggestion(location, title, icon);
229     }
230 
231     public JcrNewNodeAdapter createNewGroupSuggestion() {
232         return favoritesManager.createFavoriteGroupSuggestion("");
233     }
234 
235     public Map<String, String> getAvailableGroupsNames() {
236         return favoritesManager.getGroupsNames();
237     }
238 
239     @Override
240     public void editFavorite(String relPath, String newTitle) {
241         favoritesManager.editFavorite(relPath, newTitle);
242         initializeView();
243     }
244 
245     @Override
246     public void addGroup(JcrNewNodeAdapter newGroup) {
247         favoritesManager.addGroup(newGroup);
248         initializeView();
249     }
250 
251     @Override
252     public void editGroup(String relPath, String newTitle) {
253         favoritesManager.editGroup(relPath, newTitle);
254         initializeView();
255     }
256 
257     @Override
258     public void removeGroup(String relPath) {
259         favoritesManager.removeGroup(relPath);
260         initializeView();
261     }
262 
263     @Override
264     public void setCurrentEditedItemId(String itemId) {
265         // when somebody starts to edit a EditableFavoriteItem, make sure that all the other items are set to the not-editable-state
266         for (EditableFavoriteItem editableItem : view.getEditableFavoriteItemList()) {
267             if (!itemId.equals(editableItem.getItemId())) {
268                 editableItem.setToNonEditableState();
269             }
270         }
271     }
272 
273     String getWebAppRootURI() {
274         final URI currentUri = UI.getCurrent().getPage().getLocation();
275         String instancePrefix = currentUri.getScheme() + "://" + currentUri.getHost();
276         if (currentUri.getPort() > -1) {
277             instancePrefix += ":" + currentUri.getPort();
278         }
279         instancePrefix += currentUri.getPath(); // Path contains the ctx
280         if (StringUtils.isNotBlank(currentUri.getQuery())) {
281             instancePrefix += "?" + currentUri.getQuery();
282         }
283         return instancePrefix;
284     }
285 
286     String getUrlFragmentFromURI(URI location) {
287         final String url = location.toString();
288         String instancePrefix = getWebAppRootURI();
289 
290         return url.contains(instancePrefix) ? url.substring(url.indexOf(instancePrefix) + instancePrefix.length(), url.length()) : url;
291     }
292 
293     /**
294      * This method has package visibility for testing purposes only.
295      */
296     String getCompleteURIFromFragment(final String fragment) {
297         URI uri = null;
298         try {
299             uri = new URI(fragment);
300         } catch (URISyntaxException e) {
301             log.warn("Could not create URI from fragment {}. Exception: {}", fragment, e.toString());
302         }
303         if (uri == null || uri.isAbsolute()) {
304             return fragment;
305         }
306         return getWebAppRootURI() + fragment;
307     }
308 
309     private void initializeView() {
310         boolean itemIconsVisible = hasItems() && itemsAreEditable();
311         view.init(favoritesManager.getFavorites(), createNewFavoriteSuggestion("", "", ""), createNewGroupSuggestion(), getAvailableGroupsNames(), itemIconsVisible);
312     }
313 
314 }