Project

General

Profile

Download (10.8 KB) Statistics
| Branch: | Tag: | Revision:
1
package eu.etaxonomy.vaadin.ui.navigation;
2

    
3
import java.util.Arrays;
4
import java.util.List;
5
import java.util.Stack;
6

    
7
import org.apache.commons.lang3.StringUtils;
8
import org.apache.log4j.Logger;
9
import org.springframework.beans.factory.DisposableBean;
10
import org.springframework.beans.factory.annotation.Autowired;
11
import org.springframework.context.ApplicationContext;
12
import org.springframework.context.annotation.Lazy;
13
import org.vaadin.spring.events.EventBus;
14
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
15

    
16
import com.vaadin.navigator.ViewChangeListener;
17
import com.vaadin.navigator.ViewDisplay;
18
import com.vaadin.spring.annotation.SpringView;
19
import com.vaadin.spring.annotation.UIScope;
20
import com.vaadin.spring.navigator.SpringNavigator;
21
import com.vaadin.spring.navigator.SpringViewProvider;
22
import com.vaadin.ui.Field;
23
import com.vaadin.ui.UI;
24
import com.vaadin.ui.Window;
25

    
26
import eu.etaxonomy.cdm.vaadin.event.EditorActionContext;
27
import eu.etaxonomy.vaadin.mvp.AbstractEditorPresenter;
28
import eu.etaxonomy.vaadin.mvp.AbstractPopupEditor;
29
import eu.etaxonomy.vaadin.mvp.ApplicationView;
30
import eu.etaxonomy.vaadin.ui.UIInitializedEvent;
31
import eu.etaxonomy.vaadin.ui.view.DoneWithPopupEvent;
32
import eu.etaxonomy.vaadin.ui.view.PopEditorOpenedEvent;
33
import eu.etaxonomy.vaadin.ui.view.PopupView;
34

    
35
@UIScope
36
public class NavigationManagerBean extends SpringNavigator implements NavigationManager, DisposableBean {
37

    
38
	private static final long serialVersionUID = 6599898650948333853L;
39

    
40
	private final static Logger logger = Logger.getLogger(NavigationManagerBean.class);
41

    
42
	// injecting the viewDisplay as spring bean causes problems with older cdm vaadin code
43
	// SingleComponentContainerViewDisplay for example can't be used
44
	// the viewDisplay should be configurable per UI therefore it seems more elegant to
45
	// let the UI pass the viewDisplay to the Navigator
46
//	@Autowired
47
	private ViewDisplay viewDisplay;
48

    
49
	@Autowired
50
	private SpringViewProvider viewProvider;
51

    
52
	@Autowired
53
	private List<ViewChangeListener> viewChangeListeners;
54

    
55
	@Autowired
56
	protected ApplicationContext applicationContext;
57

    
58
	protected EventBus.UIEventBus uiEventBus;
59

    
60
	/**
61
	 * if set the navigator will block all other views
62
	 * and exclusively navigates to the error view to indicate that the
63
	 * UI is disabled.
64
	 */
65
	private String uiDisabledErrorViewName = null;
66

    
67
    @Autowired
68
    protected void setViewEventBus(EventBus.UIEventBus uiEventBus){
69
        this.uiEventBus = uiEventBus;
70
        uiEventBus.subscribe(this);
71
    }
72

    
73
//    /**
74
//     * This reference will cause the scoped PermissionDebugUtils being initialized.
75
//     * It is not used in this class but attaches itself to the vaadin session
76
//     * from where it will be accessible via VaadinUserHelper.fromSession()
77
//     *
78
//     * <b>NOTE:</b> PermissionDebugUtils is only available if the spring profile "debug" is active,
79
//     * See
80
//     */
81
//    @Autowired(required=false)
82
//    private PermissionDebugUtils permissionDebugUtils;
83

    
84
	private PopupViewRegistration popupViewRegistration;
85

    
86
	private String defaultViewName = null;
87

    
88
    /*
89
     * Why UriFragmentManager must be initialized lazily:
90
     *
91
     * when the SpringVaadinServlet usually is being instantiated the ServletUIInitHandler(UIInitHandler).getBrowserDetailsUI(VaadinRequest, VaadinSession) method is called which will
92
     * 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
93
     * via Page.getCurrent() which is used in the UriFragmentManager constructor. The NavigationManagerBean is initialized with the WebapplicationContext, that is when the current ui is
94
     * not yet available, therefore the UriFragmentManager must be initialized lazily.
95
     */
96
    @Autowired
97
    @Lazy
98
	private UriFragmentManager uriFragmentManager;
99

    
100

    
101
//	public void setUriFragmentManager(UriFragmentManager uriFragmentManager) {
102
//	    this.uriFragmentManager = uriFragmentManager;
103
//	}
104

    
105

    
106
	public NavigationManagerBean() {
107
	    popupViewRegistration = new PopupViewRegistration();
108
	}
109

    
110
//	private Collection<PopupView> popupViews = new HashSet<>();
111
//	@Lazy
112
//    @Autowired(required=false)
113
//    private void popUpViews(Collection<PopupView> popupViews){
114
//        this.popupViews = popupViews;
115
//        // popupViews.forEach(view -> this.popupViews.put(view.getClass(), view));
116
//    }
117

    
118
    private <P extends PopupView> P findPopupView(Class<P> type){
119
        P viewBean = applicationContext.getBean(type);
120
        if(viewBean == null){
121
            throw new NullPointerException("no popup-view bean of type " + type.getName() + " found");
122
        }
123
        return viewBean;
124
        // return popupViews.stream().filter(p -> p.getClass().equals(type)).findFirst();
125
    }
126

    
127
	@EventBusListenerMethod
128
	protected void onUIInitialized(UIInitializedEvent e) {
129
		init(UI.getCurrent(), uriFragmentManager, viewDisplay);
130
		addProvider(viewProvider);
131
		viewChangeListeners.forEach(vcl -> addViewChangeListener(vcl));
132
	}
133

    
134
	public void navigateTo(String navigationState, boolean fireNavigationEvent) {
135
	    if(getUiDisabledErrorView() != null) {
136
	        super.navigateTo(getUiDisabledErrorView());
137
	    }
138
	    if(StringUtils.isEmpty(navigationState)){
139
            navigationState = defaultViewName;
140
        }
141
		if (fireNavigationEvent) {
142
			navigateTo(navigationState);
143
		} else {
144
			super.navigateTo(navigationState);
145
		}
146
	}
147

    
148
	@Override
149
	public void navigateTo(String navigationState) {
150
	    if(getUiDisabledErrorView() != null) {
151
            super.navigateTo(getUiDisabledErrorView());
152
        }
153
	    if(StringUtils.isEmpty(navigationState)){
154
	        navigationState = defaultViewName;
155
	    }
156
		super.navigateTo(navigationState);
157
		//eventBus.publishEvent(new NavigationEvent(navigationState));
158
	}
159

    
160
	@EventBusListenerMethod
161
	protected void onNavigationEvent(NavigationEvent e) {
162
		navigateTo(e.getViewName(), false);
163
	}
164

    
165
	@Override
166
	public <T extends PopupView> T showInPopup(Class<T> popupType, ApplicationView parentView, Field<?> targetField) {
167

    
168
	    PopupView popupView =  findPopupView(popupType);
169

    
170
	    if(AbstractPopupEditor.class.isAssignableFrom(popupView.getClass())){
171
	        if(parentView instanceof AbstractPopupEditor){
172
	            // retain the chain of EditorActionContexts when starting a new pupupEditor
173
	            Stack<EditorActionContext> parentEditorActionContext = ((AbstractPopupEditor)parentView).getEditorActionContext();
174
	            ((AbstractPopupEditor)popupView).setParentEditorActionContext(parentEditorActionContext, targetField);
175
	        }
176
	    }
177

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

    
198
		popupViewRegistration.put(window, parentView, popupView, targetField);
199

    
200
		return (T) popupView;
201
	}
202

    
203
	@Override
204
    public Field<?> targetFieldOf(PopupView popupView){
205
	    return popupViewRegistration.get(popupView);
206
	}
207

    
208
    @EventBusListenerMethod
209
	protected void onDoneWithTheEditor(DoneWithPopupEvent event) {
210

    
211
		PopupView popup = event.getPopup();
212
		if(DisposableBean.class.isAssignableFrom(popup.getClass())){
213
		    try {
214
                ((DisposableBean)popup).destroy();
215
            } catch (Exception e) {
216
                logger.error(e);
217
            }
218
		}
219
        Window window = popupViewRegistration.getWindow(popup);
220
		if (window != null) {
221
			window.close();
222
			popupViewRegistration.remove(popup);
223
		}
224
		if(AbstractPopupEditor.class.isAssignableFrom(popup.getClass())){
225
		    ((AbstractPopupEditor)popup).presenter().unsubscribeFromEventBuses();
226
		}
227

    
228
	}
229

    
230
    /**
231
     * {@inheritDoc}
232
     */
233
    @Override
234
    public void reloadCurrentView() {
235
        if(logger.isTraceEnabled()){
236
            logger.trace("reloading " + getState());
237
        }
238
        navigateTo(getState(), false);
239
    }
240

    
241
    /**
242
     * This method requires that the {@SpringView} annotation is used to set the name of the <code>View</code>.
243
     *
244
     * @return the current view name or <code>null</code>
245
     */
246
    @Override
247
    public String getCurrentViewName() {
248
        if(getCurrentView() != null){
249
            SpringView springViewAnnotation = getCurrentView().getClass().getAnnotation(SpringView.class);
250
            if(springViewAnnotation != null){
251
                return springViewAnnotation.name();
252
            }
253
        }
254
        return null;
255
    }
256

    
257
    @Override
258
    public List<String> getCurrentViewParameters(){
259
        String substate = getState();
260
        String currentViewName = getCurrentViewName();
261
        if(currentViewName != null){
262
            substate = substate.replaceAll("^" + currentViewName + "/?", "");
263

    
264
        }
265
        return Arrays.asList(substate.split("/"));
266
    }
267

    
268
    /**
269
     * {@inheritDoc}
270
     */
271
    @Override
272
    public List<AbstractEditorPresenter<?, ?>> getPopupEditorPresenters() {
273
        // TODO Auto-generated method stub
274
        return null;
275
    }
276

    
277
    /**
278
     * @return the defaultViewName
279
     */
280
    public String getDefaultViewName() {
281
        return defaultViewName;
282
    }
283

    
284
    /**
285
     * @param defaultViewName the defaultViewName to set
286
     */
287
    public void setDefaultViewName(String defaultViewName) {
288
        this.defaultViewName = defaultViewName;
289
    }
290

    
291
    public void setViewDisplay(ViewDisplay viewDisplay){
292
        this.viewDisplay = viewDisplay;
293
    }
294

    
295
    /**
296
     * implementation of the interface {@link DisposableBean} and overrides the
297
     * method in {@link Navigator} which is not an implementation of {@link DisposableBean}
298
     * in this class.
299
     */
300
    @Override
301
    public void destroy() {
302
        super.destroy();
303
        uiEventBus.unsubscribe(this);
304
        popupViewRegistration = null;
305
        // release the reference to the view kept in currentView
306
        // which could be expensive
307
        // by navigating to the default view
308
        navigateTo(defaultViewName);
309
    }
310

    
311
    public String getUiDisabledErrorView() {
312
        return uiDisabledErrorViewName;
313
    }
314

    
315
    public void setUiDisabledErrorView(String uiDisabledErrorViewName) {
316
        this.uiDisabledErrorViewName = uiDisabledErrorViewName;
317
    }
318
}
(4-4/8)