1 package eu
.etaxonomy
.vaadin
.ui
.navigation
;
3 import java
.util
.Arrays
;
5 import java
.util
.Stack
;
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
;
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
;
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
;
36 public class NavigationManagerBean
extends SpringNavigator
implements NavigationManager
, DisposableBean
{
38 private static final long serialVersionUID
= 6599898650948333853L;
40 private final static Logger logger
= Logger
.getLogger(NavigationManagerBean
.class);
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
47 private ViewDisplay viewDisplay
;
50 private SpringViewProvider viewProvider
;
53 private List
<ViewChangeListener
> viewChangeListeners
;
56 protected ApplicationContext applicationContext
;
58 protected EventBus
.UIEventBus uiEventBus
;
61 * if set the navigator will block all other views
62 * and exclusively navigates to the error view to indicate that the
65 private String uiDisabledErrorViewName
= null;
68 protected void setViewEventBus(EventBus
.UIEventBus uiEventBus
){
69 this.uiEventBus
= uiEventBus
;
70 uiEventBus
.subscribe(this);
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()
78 // * <b>NOTE:</b> PermissionDebugUtils is only available if the spring profile "debug" is active,
81 // @Autowired(required=false)
82 // private PermissionDebugUtils permissionDebugUtils;
84 private PopupViewRegistration popupViewRegistration
;
86 private String defaultViewName
= null;
89 * Why UriFragmentManager must be initialized lazily:
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.
98 private UriFragmentManager uriFragmentManager
;
101 // public void setUriFragmentManager(UriFragmentManager uriFragmentManager) {
102 // this.uriFragmentManager = uriFragmentManager;
106 public NavigationManagerBean() {
107 popupViewRegistration
= new PopupViewRegistration();
110 // private Collection<PopupView> popupViews = new HashSet<>();
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));
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");
124 // return popupViews.stream().filter(p -> p.getClass().equals(type)).findFirst();
127 @EventBusListenerMethod
128 protected void onUIInitialized(UIInitializedEvent e
) {
129 init(UI
.getCurrent(), uriFragmentManager
, viewDisplay
);
130 addProvider(viewProvider
);
131 viewChangeListeners
.forEach(vcl
-> addViewChangeListener(vcl
));
134 public void navigateTo(String navigationState
, boolean fireNavigationEvent
) {
135 if(getUiDisabledErrorView() != null) {
136 super.navigateTo(getUiDisabledErrorView());
138 if(StringUtils
.isEmpty(navigationState
)){
139 navigationState
= defaultViewName
;
141 if (fireNavigationEvent
) {
142 navigateTo(navigationState
);
144 super.navigateTo(navigationState
);
149 public void navigateTo(String navigationState
) {
150 if(getUiDisabledErrorView() != null) {
151 super.navigateTo(getUiDisabledErrorView());
153 if(StringUtils
.isEmpty(navigationState
)){
154 navigationState
= defaultViewName
;
156 super.navigateTo(navigationState
);
157 //eventBus.publishEvent(new NavigationEvent(navigationState));
160 @EventBusListenerMethod
161 protected void onNavigationEvent(NavigationEvent e
) {
162 navigateTo(e
.getViewName(), false);
166 public <T
extends PopupView
> T
showInPopup(Class
<T
> popupType
, ApplicationView parentView
, Field
<?
> targetField
) {
168 PopupView popupView
= findPopupView(popupType
);
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
);
178 Window window
= new Window();
179 window
.setCaption(popupView
.getWindowCaption());
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
));
198 popupViewRegistration
.put(window
, parentView
, popupView
, targetField
);
200 return (T
) popupView
;
204 public Field
<?
> targetFieldOf(PopupView popupView
){
205 return popupViewRegistration
.get(popupView
);
208 @EventBusListenerMethod
209 protected void onDoneWithTheEditor(DoneWithPopupEvent event
) {
211 PopupView popup
= event
.getPopup();
212 if(DisposableBean
.class.isAssignableFrom(popup
.getClass())){
214 ((DisposableBean
)popup
).destroy();
215 } catch (Exception e
) {
219 Window window
= popupViewRegistration
.getWindow(popup
);
220 if (window
!= null) {
222 popupViewRegistration
.remove(popup
);
224 if(AbstractPopupEditor
.class.isAssignableFrom(popup
.getClass())){
225 ((AbstractPopupEditor
)popup
).presenter().unsubscribeFromEventBuses();
234 public void reloadCurrentView() {
235 if(logger
.isTraceEnabled()){
236 logger
.trace("reloading " + getState());
238 navigateTo(getState(), false);
242 * This method requires that the {@SpringView} annotation is used to set the name of the <code>View</code>.
244 * @return the current view name or <code>null</code>
247 public String
getCurrentViewName() {
248 if(getCurrentView() != null){
249 SpringView springViewAnnotation
= getCurrentView().getClass().getAnnotation(SpringView
.class);
250 if(springViewAnnotation
!= null){
251 return springViewAnnotation
.name();
258 public List
<String
> getCurrentViewParameters(){
259 String substate
= getState();
260 String currentViewName
= getCurrentViewName();
261 if(currentViewName
!= null){
262 substate
= substate
.replaceAll("^" + currentViewName
+ "/?", "");
265 return Arrays
.asList(substate
.split("/"));
272 public List
<AbstractEditorPresenter
<?
, ?
>> getPopupEditorPresenters() {
273 // TODO Auto-generated method stub
278 * @return the defaultViewName
280 public String
getDefaultViewName() {
281 return defaultViewName
;
285 * @param defaultViewName the defaultViewName to set
287 public void setDefaultViewName(String defaultViewName
) {
288 this.defaultViewName
= defaultViewName
;
291 public void setViewDisplay(ViewDisplay viewDisplay
){
292 this.viewDisplay
= viewDisplay
;
296 * implementation of the interface {@link DisposableBean} and overrides the
297 * method in {@link Navigator} which is not an implementation of {@link DisposableBean}
301 public void 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
);
311 public String
getUiDisabledErrorView() {
312 return uiDisabledErrorViewName
;
315 public void setUiDisabledErrorView(String uiDisabledErrorViewName
) {
316 this.uiDisabledErrorViewName
= uiDisabledErrorViewName
;