#30: Adaptives Layout (https://polymap.org/mosaic/ticket/30)
[polymap3:falkos-polymap3-rhei.git] / plugins / org.polymap.rhei.batik / src / org / polymap / rhei / batik / internal / desktop / DesktopAppWindow.java
1 /*
2  * polymap.org
3  * Copyright 2013, Falko Bräutigam. All rights reserved.
4  *
5  * This is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as
7  * published by the Free Software Foundation; either version 3.0 of
8  * the License, or (at your option) any later version.
9  *
10  * This software is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  */
15 package org.polymap.rhei.batik.internal.desktop;
16
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.graphics.Rectangle;
22 import org.eclipse.swt.layout.FormLayout;
23 import org.eclipse.swt.widgets.Composite;
24 import org.eclipse.swt.widgets.Control;
25 import org.eclipse.swt.widgets.Display;
26 import org.eclipse.swt.widgets.Shell;
27
28 import org.eclipse.rwt.lifecycle.UICallBack;
29 import org.eclipse.rwt.lifecycle.WidgetUtil;
30
31 import org.eclipse.jface.window.ApplicationWindow;
32
33 import org.eclipse.ui.forms.widgets.ScrolledPageBook;
34
35 import org.eclipse.core.runtime.IProgressMonitor;
36 import org.eclipse.core.runtime.IStatus;
37 import org.eclipse.core.runtime.Status;
38 import org.eclipse.core.runtime.jobs.Job;
39
40 import org.polymap.core.runtime.event.EventFilter;
41 import org.polymap.core.runtime.event.EventHandler;
42 import org.polymap.core.runtime.event.EventManager;
43 import org.polymap.core.ui.FormDataFactory;
44
45 import org.polymap.rhei.batik.BatikPlugin;
46 import org.polymap.rhei.batik.PanelChangeEvent;
47 import org.polymap.rhei.batik.PanelChangeEvent.TYPE;
48 import org.polymap.rhei.batik.internal.ApplicationResizeEvent;
49 import org.polymap.rhei.batik.internal.desktop.DesktopAppManager.DesktopPanelSite;
50
51 /**
52  * The main application window for the desktop.
53  *
54  * @author <a href="http://www.polymap.de">Falko Bräutigam</a>
55  */
56 abstract class DesktopAppWindow
57         extends ApplicationWindow {
58
59     private static Log log = LogFactory.getLog( DesktopAppWindow.class );
60
61     private DesktopAppManager       appManager;
62     
63     private ResizeHandler           resizeHandler = new ResizeHandler();
64
65     private Composite panels;
66
67     private Composite contents;
68
69
70     public DesktopAppWindow( DesktopAppManager appManager ) {
71         super( null );
72         this.appManager = appManager;
73         addStatusLine();
74         //addCoolBar( SWT.HORIZONTAL );
75     }
76
77
78     protected abstract Composite fillNavigationArea( Composite parent );
79
80     protected abstract Composite fillPanelArea( Composite parent );
81
82
83     @Override
84     protected Control createContents( Composite parent ) {
85         contents = (Composite)super.createContents( parent );
86         contents.setLayout( new FormLayout() );
87
88         // statusLine
89         setStatus( "Status..." );
90         Composite statusLine = (Composite)getStatusLineManager().getControl();
91         statusLine.setData( WidgetUtil.CUSTOM_VARIANT, "atlas-status"  );
92         statusLine.setBackground( null );
93         for (Control child : statusLine.getChildren()) {
94             child.setData( WidgetUtil.CUSTOM_VARIANT, "atlas-status"  );
95             child.setBackground( null );
96         }
97
98         // navi
99         Composite navi = fillNavigationArea( contents );
100         navi.setLayoutData( FormDataFactory.filled().bottom( -1 ).height( 30 ).create() );
101         navi.setData( WidgetUtil.CUSTOM_VARIANT, "atlas-navi"  );
102
103         panels = fillPanelArea( contents );
104         panels.setLayoutData( FormDataFactory.filled().top( navi, 10 ).create() );
105         panels.setData( WidgetUtil.CUSTOM_VARIANT, "atlas-panels"  );
106
107         appManager.getContext().addEventHandler( this, new EventFilter<PanelChangeEvent>() {
108             public boolean apply( PanelChangeEvent input ) {
109                 return input.getType() == TYPE.ACTIVATED;
110             }
111         });
112         
113         EventManager.instance().subscribe( resizeHandler );
114         
115         return contents;
116     }
117
118     
119
120     @Override
121     public boolean close() {
122         EventManager.instance().unsubscribe( resizeHandler );
123         return super.close();
124     }
125
126
127     @EventHandler(display=true)
128     protected void panelChanged( PanelChangeEvent ev ) {
129         DesktopPanelSite panelSite = (DesktopPanelSite)ev.getSource().getSite();
130         getShell().setText( "Mosaic - " + panelSite.getTitle() );
131         getShell().layout();
132     }
133
134
135     public void setStatus( IStatus status ) {
136         assert status != null;
137         switch (status.getSeverity()) {
138             case IStatus.OK: {
139                 getStatusLineManager().setErrorMessage( null ); 
140                 getStatusLineManager().setMessage( null );
141                 if (status != Status.OK_STATUS && status.getMessage() != null) {
142                     getStatusLineManager().setMessage( BatikPlugin.instance().imageForName( "resources/icons/ok-status.gif" ), 
143                             status.getMessage() );
144                 }
145                 break;
146             }
147             case IStatus.ERROR: {
148                 getStatusLineManager().setErrorMessage( 
149                         BatikPlugin.instance().imageForName( "resources/icons/errorstate.gif" ), status.getMessage() );
150                 break;
151             }
152             case IStatus.WARNING: {
153                 getStatusLineManager().setMessage( 
154                         BatikPlugin.instance().imageForName( "resources/icons/warningstate.gif" ), status.getMessage() );
155                 break;
156             }
157             default: {
158                 getStatusLineManager().setMessage( status.getMessage() );
159             }
160         }
161     }
162
163
164     @Override
165     protected void configureShell( final Shell shell ) {
166         super.configureShell( shell );
167         shell.setText( "Mosaic" );
168         shell.setTouchEnabled( true );
169
170         Rectangle bounds = Display.getCurrent().getBounds();
171         shell.setBounds( 0, 60, bounds.width, bounds.height - 60 );
172 //        shell.setMaximized( true );
173     }
174
175
176     private int refreshCount = 1;
177     
178     public void delayedRefresh( final Shell shell ) {
179         final Shell s = shell != null ? shell : getShell();
180         
181         // FIXME HACK! force re-layout after font sizes are known (?)
182         UICallBack.activate( getClass().getName() );
183         Job job = new Job( "Layout" ) {
184             protected IStatus run( IProgressMonitor monitor ) {
185                 s.getDisplay().asyncExec( new Runnable() {
186                     public void run() {
187                         log.info( "layout..." );
188                         s.layout();
189                         ((ScrolledPageBook)panels).reflow( true );
190
191                         Rectangle bounds = Display.getCurrent().getBounds();
192                         int random = (refreshCount++ % 3);
193                         s.setBounds( 0, 60, bounds.width, bounds.height - 60 - random );
194                         UICallBack.deactivate( getClass().getName() );
195                     }
196                 });
197                 return Status.OK_STATUS;
198             }
199         };
200         //job.setUser( true );
201         job.schedule( 1000 );
202     }
203
204     
205     @Override
206     protected int getShellStyle() {
207         // no border, no title
208         return SWT.NO_TRIM;
209     }
210
211
212     @Override
213     protected boolean showTopSeperator() {
214         return false;
215     }
216
217
218     /**
219      * 
220      */
221     class ResizeHandler {
222     
223         @EventHandler(display=true)
224         public void handleEvent( ApplicationResizeEvent ev ) {
225             Rectangle bounds = Display.getCurrent().getBounds();
226             log.info( "layout: " + bounds );
227             getShell().setBounds( 0, 60, bounds.width, bounds.height - 60 );
228             getShell().layout();
229             ((ScrolledPageBook)panels).reflow( true );
230             
231             delayedRefresh( null );
232         }
233     }
234     
235 }