001 //$HeadURL: svn+ssh://melmasry@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/portal/standard/context/control/FullScreenListener.java $ 002 /*---------------------------------------------------------------------------- 003 This file is part of deegree, http://deegree.org/ 004 Copyright (C) 2001-2009 by: 005 Department of Geography, University of Bonn 006 and 007 lat/lon GmbH 008 009 This library is free software; you can redistribute it and/or modify it under 010 the terms of the GNU Lesser General Public License as published by the Free 011 Software Foundation; either version 2.1 of the License, or (at your option) 012 any later version. 013 This library is distributed in the hope that it will be useful, but WITHOUT 014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 016 details. 017 You should have received a copy of the GNU Lesser General Public License 018 along with this library; if not, write to the Free Software Foundation, Inc., 019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 020 021 Contact information: 022 023 lat/lon GmbH 024 Aennchenstr. 19, 53177 Bonn 025 Germany 026 http://lat-lon.de/ 027 028 Department of Geography, University of Bonn 029 Prof. Dr. Klaus Greve 030 Postfach 1147, 53001 Bonn 031 Germany 032 http://www.geographie.uni-bonn.de/deegree/ 033 034 e-mail: info@deegree.org 035 ----------------------------------------------------------------------------*/ 036 037 package org.deegree.portal.standard.context.control; 038 039 import java.awt.Rectangle; 040 import java.io.IOException; 041 import java.net.MalformedURLException; 042 import java.util.HashMap; 043 import java.util.Iterator; 044 import java.util.LinkedList; 045 import java.util.List; 046 import java.util.Map; 047 048 import javax.servlet.http.HttpServletRequest; 049 import javax.servlet.http.HttpSession; 050 import javax.xml.parsers.ParserConfigurationException; 051 import javax.xml.transform.TransformerException; 052 053 import org.deegree.enterprise.control.FormEvent; 054 import org.deegree.enterprise.control.RPCMember; 055 import org.deegree.enterprise.control.RPCStruct; 056 import org.deegree.enterprise.control.RPCWebEvent; 057 import org.deegree.framework.log.ILogger; 058 import org.deegree.framework.log.LoggerFactory; 059 import org.deegree.framework.util.MapUtils; 060 import org.deegree.framework.util.Parameter; 061 import org.deegree.framework.xml.XMLFragment; 062 import org.deegree.i18n.Messages; 063 import org.deegree.model.crs.CoordinateSystem; 064 import org.deegree.model.spatialschema.Envelope; 065 import org.deegree.model.spatialschema.GeometryFactory; 066 import org.deegree.model.spatialschema.Point; 067 import org.deegree.portal.Constants; 068 import org.deegree.portal.PortalException; 069 import org.deegree.portal.context.ContextException; 070 import org.deegree.portal.context.Frontend; 071 import org.deegree.portal.context.GUIArea; 072 import org.deegree.portal.context.General; 073 import org.deegree.portal.context.GeneralExtension; 074 import org.deegree.portal.context.Module; 075 import org.deegree.portal.context.ViewContext; 076 import org.deegree.portal.context.XMLFactory; 077 import org.xml.sax.SAXException; 078 079 /** 080 * Convert the current view context to a full screen mode. It hides all the modules except the map 081 * and the toolbar. It also keeps whatever changes were made in the original context to the full 082 * screen context 083 * 084 * @author <a href="mailto:elmasry@lat-lon.de">Moataz Elmasry</a> 085 * @author last edited by: $Author: $ 086 * 087 * @version $Revision: $, $Date: 1 Jun 2007 10:12:29$ 088 */ 089 public class FullScreenListener extends AbstractContextListener { 090 091 private int width = 0; 092 093 private Map<String, String> modulesMap = null; 094 095 /** 096 * the path to where the Web Map Context files are found 097 */ 098 public static final String CONTEXTPATH = "WEB-INF/conf/igeoportal"; 099 100 private String xslFileName = null; 101 102 private HttpSession session = null; 103 104 /** 105 * A <code>String</code> defining the name of the xsl file that defines the transformation 106 * from a context to html. This must be placed, together with the map context xml and helper xsl 107 * files, under <code>${context-home}/WEB-INF/conf/igeoportal/</code>. 108 */ 109 protected static final String DEFAULT_CTXT2HTML = "WEB-INF/conf/igeoportal/context2HTML.xsl"; 110 111 private static final ILogger LOG = LoggerFactory.getLogger( ResetContextListener.class ); 112 113 private static final String DISPLAYED_MODULES = "DISPLAYED_MODULES"; 114 115 private static final String NORMALSCREEN_MAPCONTEXT = "NormalScreenMapContext"; 116 117 /* 118 * (non-Javadoc) 119 * 120 * @see org.deegree.enterprise.control.WebListener#actionPerformed(org.deegree.enterprise.control.FormEvent) 121 */ 122 @Override 123 public void actionPerformed( FormEvent event ) { 124 125 RPCWebEvent rpc = (RPCWebEvent) event; 126 127 try { 128 validate( rpc ); 129 validateCntxtProperties(); 130 initialize(); 131 } catch ( PortalException e ) { 132 LOG.logError( e.getMessage(), e ); 133 e.printStackTrace(); 134 gotoErrorPage( e.getMessage() ); 135 return; 136 } 137 138 try { 139 ViewContext fullScreenContext = setToFullScreen( rpc ); 140 setCurrentContext( fullScreenContext ); 141 } catch ( Exception e ) { 142 LOG.logError( e.getMessage(), e ); 143 e.printStackTrace(); 144 gotoErrorPage( e.getMessage() ); 145 return; 146 } 147 } 148 149 /** 150 * ValidateRPC looks in the RPCStruct for all needed elements and gotoErrorPage in case an 151 * element is found or wronglz formated, this is useful so that we won't need to check later for 152 * anz variables, simply get them and start Working 153 * 154 * @param rpc 155 * @throws PortalException 156 */ 157 protected void validate( RPCWebEvent rpc ) 158 throws PortalException { 159 160 RPCStruct struct = extractRPCStruct( rpc, 0 ); 161 162 RPCMember layerListRPC = struct.getMember( "layerList" ); 163 validateLayerList( layerListRPC ); 164 165 RPCMember bboxRPC = struct.getMember( "boundingBox" ); 166 validateBBox( bboxRPC ); 167 } 168 169 /** 170 * This method checks the context.properties file to make sure that all fields needed are 171 * available 172 * 173 */ 174 protected void validateCntxtProperties() 175 throws PortalException { 176 177 String displayedModules = ContextMessages.getString( DISPLAYED_MODULES ); 178 if ( displayedModules == null ) { 179 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE", 180 ContextMessages.getName(), "DISPLAYED_MODULES" ) ); 181 } 182 183 if ( displayedModules.indexOf( "MANDATORY_MODULE_MAP" ) < 0 ) { 184 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE", 185 ContextMessages.getName(), "MANDATORY_MODULE_MAP" ) ); 186 } 187 188 if ( displayedModules.indexOf( "MANDATORY_MODULE_TOOLBAR" ) < 0 ) { 189 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE", 190 ContextMessages.getName(), "MANDATORY_MODULE_TOOLBAR" ) ); 191 } 192 193 String mapName = ContextMessages.getString( "MANDATORY_MODULE_MAP" ); 194 if ( mapName == null ) { 195 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MAND_PARAM", 196 ContextMessages.getName(), "MANDATORY_MODULE_MAP" ) ); 197 } 198 199 String toolbarName = ContextMessages.getString( "MANDATORY_MODULE_TOOLBAR" ); 200 if ( toolbarName == null ) { 201 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MAND_PARAM", 202 ContextMessages.getName(), "MANDATORY_MODULE_TOOLBAR" ) ); 203 } 204 205 int width = Integer.parseInt( ContextMessages.getString( "MAP_WIDTH" ) ); 206 if ( width <= 0 ) { 207 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE", 208 ContextMessages.getName(), "MAP_WIDTH" ) ); 209 } 210 211 String normalScreen = ContextMessages.getString( "NORMAL_SIZE_SCREEN" ); 212 if ( normalScreen == null ) { 213 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_CONFIG_FILE", 214 ContextMessages.getName(), "NORMAL_SIZE_SCREEN" ) ); 215 } 216 } 217 218 /** 219 * Initializes the global variables 220 * 221 * @throws PortalException 222 */ 223 protected void initialize() 224 throws PortalException { 225 226 try { 227 xslFileName = "file://" + getHomePath() + DEFAULT_CTXT2HTML; 228 229 width = Integer.parseInt( ContextMessages.getString( "MAP_WIDTH" ) ); 230 session = ( (HttpServletRequest) this.getRequest() ).getSession(); 231 232 modulesMap = loadModulesNames( DISPLAYED_MODULES ); 233 } catch ( Exception e ) { 234 LOG.logError( e.getMessage() ); 235 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_INITIALIZE", e ) ); 236 } 237 } 238 239 /** 240 * Applies the modules read from the context.properties file to the current context using the 241 * data from the session on the defaultContext 242 * 243 * @param rpc 244 * @return the view context for full screen 245 * @throws ParserConfigurationException 246 * @throws PortalException 247 * @throws ContextException 248 */ 249 protected ViewContext setToFullScreen( RPCWebEvent rpc ) 250 throws ParserConfigurationException, PortalException, ContextException { 251 252 RPCStruct struct = extractRPCStruct( rpc, 0 ); 253 ViewContext tempContext = applyLayers( struct ); 254 255 try { 256 XMLFragment xmlActualContext = XMLFactory.export( tempContext ); 257 // Saving the original Context 258 session.setAttribute( NORMALSCREEN_MAPCONTEXT, xmlActualContext ); 259 } catch ( ParserConfigurationException e ) { 260 LOG.logError( e.getMessage() ); 261 throw new ParserConfigurationException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_TRANSFORM" ) ); 262 } 263 return createFullScreenContext( struct, tempContext ); 264 } 265 266 /** 267 * Takes in viewContext converts it to a html of the viewcontext and display it 268 * 269 * @param vc the Viewcontext after convert 270 * @throws ParserConfigurationException 271 * @throws TransformerException 272 * @throws SAXException 273 * @throws MalformedURLException 274 * @throws IOException 275 */ 276 protected void setCurrentContext( ViewContext vc ) 277 throws ParserConfigurationException, TransformerException, SAXException, 278 MalformedURLException, IOException { 279 280 try { 281 XMLFragment xml = XMLFactory.export( vc ); 282 String newHtml = transformToHtmlMapContext( xml, xslFileName ); 283 session.setAttribute( ContextSwitchListener.NEW_CONTEXT_HTML, newHtml ); 284 } catch ( ParserConfigurationException e ) { 285 LOG.logError( e.getMessage() ); 286 throw new ParserConfigurationException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_TRANSFORM" ) ); 287 } 288 } 289 290 /** 291 * Gets the current map context from the session and applies the current layers to it. 292 * 293 * @param struct 294 * @return the viewContext after applying the current layers to it 295 * @throws PortalException 296 */ 297 private ViewContext applyLayers( RPCStruct struct ) 298 throws PortalException { 299 300 ViewContext tempContext = null; 301 try { 302 String sessionId = (String) session.getAttribute( "SESSIONID" ); 303 ViewContext vc = (ViewContext) session.getAttribute( Constants.CURRENTMAPCONTEXT ); 304 tempContext = vc.clone( null, sessionId ); 305 306 // Applying the layer setting to the current context 307 RPCMember[] layerList = ( (RPCStruct) struct.getMember( "layerList" ).getValue() ).getMembers(); 308 changeLayerList( tempContext, layerList ); 309 310 } catch ( PortalException e ) { 311 // throw new PortalException( Messages.getMessage( 312 // "IGEO_STD_CNTXT_ERROR_EMPTY_LAYERLIST" ) ); 313 throw e; 314 } catch ( Exception e ) { 315 LOG.logError( e.getMessage() ); 316 throw new PortalException( Messages.getMessage( "IGEO_STD_ERROR_UNKNOWN", e ) ); 317 } 318 return tempContext; 319 } 320 321 /** 322 * Validates the data in the struct to make sure it contains a valid layerList 323 * 324 * @param layerListRPCMember 325 * @throws PortalException 326 */ 327 protected void validateLayerList( RPCMember layerListRPCMember ) 328 throws PortalException { 329 330 if ( layerListRPCMember == null || layerListRPCMember.getValue() == null ) { 331 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_RPC_MEMBER", "layerList" ) ); 332 } 333 334 RPCMember[] layerList = null; 335 try { 336 layerList = ( (RPCStruct) layerListRPCMember.getValue() ).getMembers(); 337 } catch ( Exception e ) { 338 LOG.logError( e.getMessage() ); 339 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_WRONG_RPC_MEMBER_VALUE", "layerList" ) ); 340 } 341 342 if ( layerList == null || layerList.length < 1 ) { 343 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_EMPTY_LAYERLIST", "layerList" ) ); 344 } 345 } 346 347 /** 348 * Validates the data in the struct to make sure it contains a valid bbox 349 * 350 * @param bboxRPCMember 351 * @throws PortalException 352 */ 353 protected void validateBBox( RPCMember bboxRPCMember ) 354 throws PortalException { 355 356 if ( bboxRPCMember == null || bboxRPCMember.getValue() == null ) { 357 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_RPC_MEMBER", "boundingBox" ) ); 358 } 359 360 RPCStruct bboxStruct = (RPCStruct) bboxRPCMember.getValue(); 361 Double minx = null; 362 Double miny = null; 363 Double maxx = null; 364 Double maxy = null; 365 366 RPCMember mem = bboxStruct.getMember( Constants.RPC_BBOXMINX ); 367 if ( mem != null ) { 368 minx = (Double) mem.getValue(); 369 } 370 mem = bboxStruct.getMember( Constants.RPC_BBOXMINY ); 371 if ( mem != null ) { 372 miny = (Double) mem.getValue(); 373 } 374 mem = bboxStruct.getMember( Constants.RPC_BBOXMAXX ); 375 if ( mem != null ) { 376 maxx = (Double) mem.getValue(); 377 } 378 mem = bboxStruct.getMember( Constants.RPC_BBOXMAXY ); 379 if ( mem != null ) { 380 maxy = (Double) mem.getValue(); 381 } 382 383 if ( minx == null || maxx == null || miny == null || maxy == null ) { 384 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_WRONG_RPC_MEMBER_VALUE", "boundingBox" ) ); 385 } 386 if ( minx >= maxx || miny >= maxy ) { 387 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_BBOX_BOUNDARIES" ) ); 388 } 389 } 390 391 /** 392 * Extracts shown modules names from the context.properties file 393 * 394 * @param selectedModules 395 * The modules names key as written in the context.properties file 396 * @return Map contains all the used modules 397 */ 398 private Map<String, String> loadModulesNames( String selectedModules ) { 399 400 String modulesNames = ContextMessages.getString( selectedModules ); 401 Map<String, String> modules = new HashMap<String, String>(); 402 String[] tmpNames = modulesNames.split( ";" ); 403 for ( int i = 0; i < tmpNames.length; i++ ) { 404 String value = ContextMessages.getString( tmpNames[i] ); 405 if ( tmpNames[i] != null && value != null ) { 406 modules.put( tmpNames[i], value ); 407 } 408 } 409 return modules; 410 } 411 412 /** 413 * Sets the given context to FullScreen mode. 414 * 415 * @param struct the rpc struct containing the current bbox envelope 416 * @param vc view context with the layers 417 * @return The context transformed to the fullScreen size 418 * @throws ContextException 419 * @throws PortalException 420 */ 421 protected ViewContext createFullScreenContext( RPCStruct struct, ViewContext vc ) 422 throws ContextException, PortalException { 423 424 RPCStruct bBoxStruct = (RPCStruct) struct.getMember( "boundingBox" ).getValue(); 425 Envelope envelope = extractBBox( bBoxStruct, null ); 426 427 String sessionID = (String) session.getAttribute( "SESSIONID" ); 428 ViewContext fullscreenContext = null; 429 try { 430 fullscreenContext = vc.clone( null, sessionID ); 431 } catch ( Exception e ) { 432 throw new ContextException( "The view context couldn't be cloned" ); 433 } 434 General general = fullscreenContext.getGeneral(); 435 GeneralExtension extension = general.getExtension(); 436 Frontend frontEnd = extension.getFrontend(); 437 438 // The bbox values are changed here 439 Point[] points = general.getBoundingBox(); 440 // if there are no 2 points, then nothing happens 441 if ( points.length == 2 ) { 442 Rectangle rect = general.getWindow(); 443 rect.width = width; // setting new window width 444 CoordinateSystem crs = points[0].getCoordinateSystem(); 445 Envelope bbox = MapUtils.ensureAspectRatio( envelope, rect.width, rect.height ); 446 447 Point[] newPoints = new Point[2]; 448 newPoints[0] = GeometryFactory.createPoint( bbox.getMin(), crs ); 449 newPoints[1] = GeometryFactory.createPoint( bbox.getMax(), crs ); 450 451 general.setBoundingBox( newPoints ); 452 } else { 453 throw new ContextException( Messages.getMessage( "IGEO_STD_CNTXT_ERROR_VIEWCONTEXT", "bounding box" ) ); 454 } 455 456 // Here removing all the side modules 457 List<GUIArea> contextAreas = new LinkedList<GUIArea>(); 458 // Makign sure we fetched the names right, otherwise we don't have the names to compare with 459 460 // Adding GuiAreas to a list to do a for loop 461 // instead of accessing them individually 462 GUIArea curArea = null; 463 if ( ( curArea = frontEnd.getNorth() ) != null ) { 464 contextAreas.add( curArea ); 465 } 466 if ( ( curArea = frontEnd.getSouth() ) != null ) { 467 contextAreas.add( curArea ); 468 } 469 if ( ( curArea = frontEnd.getEast() ) != null ) { 470 contextAreas.add( curArea ); 471 } 472 if ( ( curArea = frontEnd.getWest() ) != null ) { 473 contextAreas.add( curArea ); 474 } 475 if ( ( curArea = frontEnd.getCenter() ) != null ) { 476 contextAreas.add( curArea ); 477 } 478 479 Iterator<GUIArea> it = contextAreas.iterator(); 480 481 // We now know for sure, that will find the map and the toolbar 482 // since we already called validateCntxtProperties() 483 boolean mapFound = false; 484 boolean toolbarFound = false; 485 while ( it.hasNext() ) { 486 GUIArea area = it.next(); 487 boolean found = false; 488 489 Module[] modules = area.getModules(); 490 for ( int i = 0; i < modules.length; i++ ) { 491 // If the module name was in the list of shownModules then keep it 492 if ( modulesMap.containsValue( modules[i].getName() ) ) { 493 found = true; 494 if ( modules[i].getName().compareTo( modulesMap.get( "MANDATORY_MODULE_MAP" ) ) == 0 ) { 495 // The map view or the tool bar has been found 496 modules[i].setWidth( width ); 497 mapFound = true; 498 } 499 500 if ( modules[i].getName().compareTo( modulesMap.get( "MANDATORY_MODULE_TOOLBAR" ) ) == 0 ) { 501 modules[i].setWidth( width ); 502 toolbarFound = true; 503 } 504 continue; 505 } 506 modules[i].setHidden( true ); 507 } 508 if ( !found ) { 509 area.setArea( 0 ); 510 area.setHidden( true ); 511 } 512 } 513 514 if ( !mapFound ) { 515 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MODULE", 516 modulesMap.get( "MANDATORY_MODULE_MAP" ) ) ); 517 } 518 if ( !toolbarFound ) { 519 throw new PortalException( Messages.getMessage( "IGEO_STD_CNTXT_MISSING_MODULE", 520 modulesMap.get( "MANDATORY_MODULE_TOOLBAR" ) ) ); 521 } 522 523 // Changing the full screen button to normal size screen button 524 Module toolBar = frontEnd.getCenter().getModule( "Toolbar" ); 525 if ( toolBar != null ) { 526 String[] removedBtns = ContextMessages.getString( "REMOVED_BUTTONS" ).split( ";" ); 527 528 // Remove only the parameters that exist in the hash map 529 String[] names = toolBar.getParameter().getParameterNames(); 530 for ( int i = 0; i < names.length; i++ ) { 531 for ( int j = 0; j < removedBtns.length; j++ ) { 532 if ( names[i].indexOf( removedBtns[j] ) >= 0 ) { 533 toolBar.getParameter().removeParameter( names[i] ); 534 } 535 } 536 } 537 } 538 539 Parameter param = new Parameter( ContextMessages.getString( "NORMAL_SIZE_SCREEN" ), "PushButton" ); 540 toolBar.addParameter( param ); 541 542 return fullscreenContext; 543 } 544 }