Project

General

Profile

Download (11 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2017 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.vaadin.ui.navigation;
10

    
11
import java.util.Arrays;
12
import java.util.List;
13
import java.util.Stack;
14

    
15
import org.apache.commons.lang3.StringUtils;
16
import org.apache.logging.log4j.LogManager;
17
import org.apache.logging.log4j.Logger;
18
import org.springframework.beans.factory.DisposableBean;
19
import org.springframework.beans.factory.annotation.Autowired;
20
import org.springframework.context.ApplicationContext;
21
import org.springframework.context.annotation.Lazy;
22
import org.vaadin.spring.events.EventBus;
23
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
24

    
25
import com.vaadin.navigator.ViewChangeListener;
26
import com.vaadin.navigator.ViewDisplay;
27
import com.vaadin.spring.annotation.SpringView;
28
import com.vaadin.spring.annotation.UIScope;
29
import com.vaadin.spring.navigator.SpringNavigator;
30
import com.vaadin.spring.navigator.SpringViewProvider;
31
import com.vaadin.ui.Field;
32
import com.vaadin.ui.UI;
33
import com.vaadin.ui.Window;
34

    
35
import eu.etaxonomy.cdm.vaadin.event.EditorActionContext;
36
import eu.etaxonomy.vaadin.mvp.AbstractEditorPresenter;
37
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
38
import eu.etaxonomy.vaadin.mvp.ApplicationView;
39
import eu.etaxonomy.vaadin.ui.UIInitializedEvent;
40
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
41
import eu.etaxonomy.vaadin.ui.view.PopEditorOpenedEvent;
42
import eu.etaxonomy.vaadin.ui.view.PopupView;
43

    
44
@UIScope
45
public class NavigationManagerBean extends SpringNavigator implements NavigationManager, DisposableBean {
46

    
47
	private static final long serialVersionUID = 6599898650948333853L;
48

    
49
    private final static Logger logger = LogManager.getLogger();
50

    
51
	// injecting the viewDisplay as spring bean causes problems with older cdm vaadin code
52
	// SingleComponentContainerViewDisplay for example can't be used
53
	// the viewDisplay should be configurable per UI therefore it seems more elegant to
54
	// let the UI pass the viewDisplay to the Navigator
55
//	@Autowired
56
	private ViewDisplay viewDisplay;
57

    
58
	@Autowired
59
	private SpringViewProvider viewProvider;
60

    
61
	@Autowired
62
	private List<ViewChangeListener> viewChangeListeners;
63

    
64
	@Autowired
65
	protected ApplicationContext applicationContext;
66

    
67
	protected EventBus.UIEventBus uiEventBus;
68

    
69
	/**
70
	 * if set the navigator will block all other views
71
	 * and exclusively navigates to the error view to indicate that the
72
	 * UI is disabled.
73
	 */
74
	private String uiDisabledErrorViewName = null;
75

    
76
    @Autowired
77
    protected void setViewEventBus(EventBus.UIEventBus uiEventBus){
78
        this.uiEventBus = uiEventBus;
79
        uiEventBus.subscribe(this);
80
    }
81

    
82
//    /**
83
//     * This reference will cause the scoped PermissionDebugUtils being initialized.
84
//     * It is not used in this class but attaches itself to the vaadin session
85
//     * from where it will be accessible via VaadinUserHelper.fromSession()
86
//     *
87
//     * <b>NOTE:</b> PermissionDebugUtils is only available if the spring profile "debug" is active,
88
//     * See
89
//     */
90
//    @Autowired(required=false)
91
//    private PermissionDebugUtils permissionDebugUtils;
92

    
93
	private PopupViewRegistration popupViewRegistration;
94

    
95
	private String defaultViewName = null;
96

    
97
    /*
98
     * Why UriFragmentManager must be initialized lazily:
99
     *
100
     * when the SpringVaadinServlet usually is being instantiated the ServletUIInitHandler(UIInitHandler).getBrowserDetailsUI(VaadinRequest, VaadinSession) method is called which will
101
     * first cause the WebapplicationContext being created. Once this is done the initialization of the UI classes is completed. This means that the UI classes are not readily available
102
     * via Page.getCurrent() which is used in the UriFragmentManager constructor. The NavigationManagerBean is initialized with the WebapplicationContext, that is when the current ui is
103
     * not yet available, therefore the UriFragmentManager must be initialized lazily.
104
     */
105
    @Autowired
106
    @Lazy
107
	private UriFragmentManager uriFragmentManager;
108

    
109

    
110
//	public void setUriFragmentManager(UriFragmentManager uriFragmentManager) {
111
//	    this.uriFragmentManager = uriFragmentManager;
112
//	}
113

    
114

    
115
	public NavigationManagerBean() {
116
	    popupViewRegistration = new PopupViewRegistration();
117
	}
118

    
119
//	private Collection<PopupView> popupViews = new HashSet<>();
120
//	@Lazy
121
//    @Autowired(required=false)
122
//    private void popUpViews(Collection<PopupView> popupViews){
123
//        this.popupViews = popupViews;
124
//        // popupViews.forEach(view -> this.popupViews.put(view.getClass(), view));
125
//    }
126

    
127
    private <P extends PopupView> P findPopupView(Class<P> type){
128
        P viewBean = applicationContext.getBean(type);
129
        if(viewBean == null){
130
            throw new NullPointerException("no popup-view bean of type " + type.getName() + " found");
131
        }
132
        return viewBean;
133
        // return popupViews.stream().filter(p -> p.getClass().equals(type)).findFirst();
134
    }
135

    
136
	@EventBusListenerMethod
137
	protected void onUIInitialized(UIInitializedEvent e) {
138
		init(UI.getCurrent(), uriFragmentManager, viewDisplay);
139
		addProvider(viewProvider);
140
		viewChangeListeners.forEach(vcl -> addViewChangeListener(vcl));
141
	}
142

    
143
	public void navigateTo(String navigationState, boolean fireNavigationEvent) {
144
	    if(getUiDisabledErrorView() != null) {
145
	        super.navigateTo(getUiDisabledErrorView());
146
	    }
147
	    if(StringUtils.isEmpty(navigationState)){
148
            navigationState = defaultViewName;
149
        }
150
		if (fireNavigationEvent) {
151
			navigateTo(navigationState);
152
		} else {
153
			super.navigateTo(navigationState);
154
		}
155
	}
156

    
157
	@Override
158
	public void navigateTo(String navigationState) {
159
	    if(getUiDisabledErrorView() != null) {
160
            super.navigateTo(getUiDisabledErrorView());
161
        }
162
	    if(StringUtils.isEmpty(navigationState)){
163
	        navigationState = defaultViewName;
164
	    }
165
		super.navigateTo(navigationState);
166
		//eventBus.publishEvent(new NavigationEvent(navigationState));
167
	}
168

    
169
	@EventBusListenerMethod
170
	protected void onNavigationEvent(NavigationEvent e) {
171
		navigateTo(e.getViewName(), false);
172
	}
173

    
174
	@Override
175
	public <T extends PopupView> T showInPopup(Class<T> popupType, ApplicationView parentView, Field<?> targetField) {
176

    
177
	    PopupView popupView =  findPopupView(popupType);
178

    
179
	    if(AbstractPopupEditor.class.isAssignableFrom(popupView.getClass())){
180
	        if(parentView instanceof AbstractPopupEditor){
181
	            // retain the chain of EditorActionContexts when starting a new pupupEditor
182
	            Stack<EditorActionContext> parentEditorActionContext = ((AbstractPopupEditor)parentView).getEditorActionContext();
183
	            ((AbstractPopupEditor)popupView).setParentEditorActionContext(parentEditorActionContext, targetField);
184
	        }
185
	    }
186

    
187
		Window window = new Window();
188
		window.setCaption(popupView.getWindowCaption());
189
		window.center();
190
		window.setResizable(popupView.isResizable());
191
		// due to issue #6673 (https://dev.e-taxonomy.eu/redmine/issues/6673) popup editors must be modal!
192
		//window.setModal(popupView.isModal());
193
		window.setModal(true);
194
		window.setCaptionAsHtml(popupView.isWindowCaptionAsHtml());
195
		window.setWidth(popupView.getWindowWidth(), popupView.getWindowWidthUnit());
196
		window.setHeight(popupView.getWindowHeight(), popupView.getWindowHeightUnit());
197
		window.setContent(popupView.asComponent());
198
		// TODO need to disallow pressing the close [x] button:
199
		// since window.addCloseListener(e -> popupView.cancel()); will
200
		// cause sending cancel events even if save has been clicked
201
		window.setClosable(popupView.isClosable());
202
		UI.getCurrent().addWindow(window);
203
		popupView.viewEntered();
204
		popupView.focusFirst();
205
		uiEventBus.publish(this, new PopEditorOpenedEvent(this, popupView));
206

    
207
		popupViewRegistration.put(window, parentView, popupView, targetField);
208

    
209
		return (T) popupView;
210
	}
211

    
212
	@Override
213
    public Field<?> targetFieldOf(PopupView popupView){
214
	    return popupViewRegistration.get(popupView);
215
	}
216

    
217
    @EventBusListenerMethod
218
	protected void onDoneWithTheEditor(DoneWithPopupEvent event) {
219

    
220
		PopupView popup = event.getPopup();
221
		if(DisposableBean.class.isAssignableFrom(popup.getClass())){
222
		    try {
223
                ((DisposableBean)popup).destroy();
224
            } catch (Exception e) {
225
                logger.error(e);
226
            }
227
		}
228
        Window window = popupViewRegistration.getWindow(popup);
229
		if (window != null) {
230
			window.close();
231
			popupViewRegistration.remove(popup);
232
		}
233
		if(AbstractPopupEditor.class.isAssignableFrom(popup.getClass())){
234
		    ((AbstractPopupEditor)popup).presenter().unsubscribeFromEventBuses();
235
		}
236

    
237
	}
238

    
239
    /**
240
     * {@inheritDoc}
241
     */
242
    @Override
243
    public void reloadCurrentView() {
244
        if(logger.isTraceEnabled()){
245
            logger.trace("reloading " + getState());
246
        }
247
        navigateTo(getState(), false);
248
    }
249

    
250
    /**
251
     * This method requires that the {@SpringView} annotation is used to set the name of the <code>View</code>.
252
     *
253
     * @return the current view name or <code>null</code>
254
     */
255
    @Override
256
    public String getCurrentViewName() {
257
        if(getCurrentView() != null){
258
            SpringView springViewAnnotation = getCurrentView().getClass().getAnnotation(SpringView.class);
259
            if(springViewAnnotation != null){
260
                return springViewAnnotation.name();
261
            }
262
        }
263
        return null;
264
    }
265

    
266
    @Override
267
    public List<String> getCurrentViewParameters(){
268
        String substate = getState();
269
        String currentViewName = getCurrentViewName();
270
        if(currentViewName != null){
271
            substate = substate.replaceAll("^" + currentViewName + "/?", "");
272

    
273
        }
274
        return Arrays.asList(substate.split("/"));
275
    }
276

    
277
    /**
278
     * {@inheritDoc}
279
     */
280
    @Override
281
    public List<AbstractEditorPresenter<?, ?>> getPopupEditorPresenters() {
282
        // TODO Auto-generated method stub
283
        return null;
284
    }
285

    
286
    /**
287
     * @return the defaultViewName
288
     */
289
    public String getDefaultViewName() {
290
        return defaultViewName;
291
    }
292

    
293
    /**
294
     * @param defaultViewName the defaultViewName to set
295
     */
296
    public void setDefaultViewName(String defaultViewName) {
297
        this.defaultViewName = defaultViewName;
298
    }
299

    
300
    public void setViewDisplay(ViewDisplay viewDisplay){
301
        this.viewDisplay = viewDisplay;
302
    }
303

    
304
    /**
305
     * implementation of the interface {@link DisposableBean} and overrides the
306
     * method in {@link Navigator} which is not an implementation of {@link DisposableBean}
307
     * in this class.
308
     */
309
    @Override
310
    public void destroy() {
311
        super.destroy();
312
        uiEventBus.unsubscribe(this);
313
        popupViewRegistration = null;
314
        // release the reference to the view kept in currentView
315
        // which could be expensive
316
        // by navigating to the default view
317
        navigateTo(defaultViewName);
318
    }
319

    
320
    public String getUiDisabledErrorView() {
321
        return uiDisabledErrorViewName;
322
    }
323

    
324
    public void setUiDisabledErrorView(String uiDisabledErrorViewName) {
325
        this.uiDisabledErrorViewName = uiDisabledErrorViewName;
326
    }
327
}
(4-4/8)