001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.workplace; 029 030import org.opencms.configuration.CmsDefaultUserSettings; 031import org.opencms.db.CmsUserSettings; 032import org.opencms.file.CmsProject; 033import org.opencms.file.CmsResourceFilter; 034import org.opencms.i18n.CmsEncoder; 035import org.opencms.jsp.CmsJspActionElement; 036import org.opencms.main.CmsException; 037import org.opencms.main.CmsLog; 038import org.opencms.main.OpenCms; 039import org.opencms.security.CmsOrganizationalUnit; 040import org.opencms.site.CmsSite; 041import org.opencms.synchronize.CmsSynchronizeSettings; 042import org.opencms.util.CmsFileUtil; 043import org.opencms.util.CmsRequestUtil; 044import org.opencms.util.CmsStringUtil; 045 046import java.util.ArrayList; 047import java.util.Arrays; 048import java.util.Collections; 049import java.util.Iterator; 050import java.util.List; 051import java.util.Map.Entry; 052import java.util.Set; 053 054import javax.servlet.http.HttpServletRequest; 055import javax.servlet.http.HttpSession; 056 057import org.apache.commons.logging.Log; 058 059/** 060 * Provides methods for building the main framesets of the OpenCms Workplace.<p> 061 * 062 * The following files use this class: 063 * <ul> 064 * <li>/views/top.html 065 * <li>/views/top_foot.html 066 * <li>/views/top_head.html 067 * </ul> 068 * <p> 069 * 070 * @since 6.0.0 071 */ 072public class CmsFrameset extends CmsWorkplace { 073 074 /** Path to the JSP workplace frame loader file. */ 075 public static final String JSP_WORKPLACE_URI = CmsWorkplace.JSP_WORKPLACE_URI; 076 077 /** The request parameter for the selection of the frame. */ 078 public static final String PARAM_WP_FRAME = "wpFrame"; 079 080 /** The request parameter for the workplace start selection. */ 081 public static final String PARAM_WP_START = "wpStart"; 082 083 /** The request parameter for the workplace view selection. */ 084 public static final String PARAM_WP_VIEW = "wpView"; 085 086 /** The names of the supported frames. */ 087 private static final String[] FRAMES = {"top", "head", "body", "foot"}; 088 089 /** The names of the supported frames in a list. */ 090 public static final List<String> FRAMES_LIST = Collections.unmodifiableList(Arrays.asList(FRAMES)); 091 092 /** The log object for this class. */ 093 private static final Log LOG = CmsLog.getLog(CmsFrameset.class); 094 095 /** Indicates if a reload of the main body frame is required. */ 096 private boolean m_reloadRequired; 097 098 /** 099 * Public constructor.<p> 100 * 101 * @param jsp an initialized JSP action element 102 */ 103 public CmsFrameset(CmsJspActionElement jsp) { 104 105 super(jsp); 106 } 107 108 /** 109 * Performs additional filtering on the list of projects for the project selector.<p> 110 * 111 * @param projects the original project list 112 * 113 * @return the filtered project list 114 */ 115 public List<CmsProject> filterProjectsForSelector(List<CmsProject> projects) { 116 117 List<CmsProject> result = new ArrayList<CmsProject>(); 118 for (CmsProject project : projects) { 119 if (!project.isHiddenFromSelector()) { 120 result.add(project); 121 } 122 } 123 return result; 124 } 125 126 /** 127 * Returns the javascript code for the broadcast message alert in the foot of the workplace.<p> 128 * 129 * @return javascript code showing an alert box when the foot load 130 */ 131 public String getBroadcastMessage() { 132 133 StringBuffer result = new StringBuffer(512); 134 String message = getBroadcastMessageString(); 135 136 if (CmsStringUtil.isNotEmpty(message)) { 137 // create a javascript alert for the message 138 result.append("\n<script >\n<!--\n"); 139 // the timeout gives the frameset enough time to load before the alert is shown 140 result.append("function showMessage() {\n"); 141 result.append("\talert(decodeURIComponent(\""); 142 // the user has pending messages, display them all 143 result.append(CmsEncoder.escapeWBlanks(message, CmsEncoder.ENCODING_UTF_8)); 144 result.append("\"));\n}\n"); 145 result.append("setTimeout('showMessage();', 2000);"); 146 result.append("\n//-->\n</script>"); 147 } 148 return result.toString(); 149 } 150 151 /** 152 * Returns the remote ip address of the current user.<p> 153 * 154 * @return the remote ip address of the current user 155 */ 156 public String getLoginAddress() { 157 158 return getCms().getRequestContext().getRemoteAddress(); 159 } 160 161 /** 162 * Returns the last login time of the current user in localized format.<p> 163 * 164 * @return the last login time of the current user in localized format 165 */ 166 public String getLoginTime() { 167 168 return getMessages().getDateTime(getSettings().getUser().getLastlogin()); 169 } 170 171 /** 172 * Returns the html for the "preferences" button depending on the current users permissions and 173 * the default workplace settings.<p> 174 * 175 * @return the html for the "preferences" button 176 */ 177 public String getPreferencesButton() { 178 179 int buttonStyle = getSettings().getUserSettings().getWorkplaceButtonStyle(); 180 if (!getCms().getRequestContext().getCurrentUser().isManaged()) { 181 return button( 182 "../commons/preferences.jsp", 183 "body", 184 "preferences.png", 185 Messages.GUI_BUTTON_PREFERENCES_0, 186 buttonStyle); 187 } else { 188 return button(null, null, "preferences_in.png", Messages.GUI_BUTTON_PREFERENCES_0, buttonStyle); 189 } 190 } 191 192 /** 193 * Returns a html select box filled with the current users accessible projects.<p> 194 * 195 * @param htmlAttributes attributes that will be inserted into the generated html 196 * @param htmlWidth additional style attributes containing width information 197 * @return a html select box filled with the current users accessible projects 198 */ 199 public String getProjectSelect(String htmlAttributes, String htmlWidth) { 200 201 // get all project information 202 List<CmsProject> allProjects; 203 try { 204 String ouFqn = ""; 205 CmsUserSettings settings = new CmsUserSettings(getCms()); 206 if (!settings.getListAllProjects()) { 207 ouFqn = getCms().getRequestContext().getCurrentUser().getOuFqn(); 208 } 209 allProjects = OpenCms.getOrgUnitManager().getAllAccessibleProjects( 210 getCms(), 211 ouFqn, 212 settings.getListAllProjects()); 213 } catch (CmsException e) { 214 // should usually never happen 215 if (LOG.isErrorEnabled()) { 216 LOG.error(e.getLocalizedMessage(), e); 217 } 218 allProjects = Collections.emptyList(); 219 } 220 allProjects = filterProjectsForSelector(allProjects); 221 222 boolean singleOu = true; 223 String ouFqn = null; 224 Iterator<CmsProject> itProjects = allProjects.iterator(); 225 while (itProjects.hasNext()) { 226 CmsProject prj = itProjects.next(); 227 if (prj.isOnlineProject()) { 228 // skip the online project 229 continue; 230 } 231 if (ouFqn == null) { 232 // set the first ou 233 ouFqn = prj.getOuFqn(); 234 } 235 if (!ouFqn.equals(prj.getOuFqn())) { 236 // break if one different ou is found 237 singleOu = false; 238 break; 239 } 240 } 241 242 List<String> options = new ArrayList<String>(); 243 List<String> values = new ArrayList<String>(); 244 int selectedIndex = -1; 245 int ouDefaultProjIndex = -1; 246 247 CmsOrganizationalUnit ou = null; 248 try { 249 ou = OpenCms.getOrgUnitManager().readOrganizationalUnit(getCms(), getCms().getRequestContext().getOuFqn()); 250 } catch (CmsException e) { 251 // should never happen, ignore 252 } 253 254 // now loop through all projects and fill the result vectors 255 for (int i = 0, n = allProjects.size(); i < n; i++) { 256 CmsProject project = allProjects.get(i); 257 String projectId = project.getUuid().toString(); 258 String projectName = project.getSimpleName(); 259 if (!singleOu && !project.isOnlineProject()) { 260 try { 261 projectName = projectName 262 + " - " 263 + OpenCms.getOrgUnitManager().readOrganizationalUnit( 264 getCms(), 265 project.getOuFqn()).getDisplayName(getLocale()); 266 } catch (CmsException e) { 267 projectName = projectName + " - " + project.getOuFqn(); 268 } 269 } 270 271 values.add(projectId); 272 options.add(projectName); 273 274 if (project.getUuid().equals(getSettings().getProject())) { 275 // this is the user's current project 276 selectedIndex = i; 277 } 278 if ((ou != null) && project.getUuid().equals(ou.getProjectId())) { 279 ouDefaultProjIndex = i; 280 } 281 } 282 if (selectedIndex == -1) { 283 if (ouDefaultProjIndex == -1) { 284 selectedIndex = 0; 285 } else { 286 selectedIndex = ouDefaultProjIndex; 287 } 288 } 289 if (CmsStringUtil.isNotEmpty(htmlWidth)) { 290 StringBuffer buf = new StringBuffer(htmlAttributes.length() + htmlWidth.length() + 2); 291 buf.append(htmlAttributes); 292 buf.append(" "); 293 buf.append(htmlWidth); 294 htmlAttributes = buf.toString(); 295 } 296 297 return buildSelect(htmlAttributes, options, values, selectedIndex); 298 } 299 300 /** 301 * Returns the html for the "publish project" button depending on the current users permissions and the default 302 * workplace settings.<p> 303 * 304 * @return the html for the "publish project" button 305 */ 306 public String getPublishButton() { 307 308 String publishButton = OpenCms.getWorkplaceManager().getDefaultUserSettings().getPublishButtonAppearance(); 309 if (CmsDefaultUserSettings.PUBLISHBUTTON_SHOW_NEVER.equals(publishButton)) { 310 return ""; 311 } 312 313 int buttonStyle = getSettings().getUserSettings().getWorkplaceButtonStyle(); 314 315 if (CmsDefaultUserSettings.PUBLISHBUTTON_SHOW_AUTO.equals(publishButton)) { 316 if (getCms().isManagerOfProject()) { 317 return button( 318 "../../workplace/commons/publish_project.jsp", 319 "body", 320 "publish.png", 321 Messages.GUI_BUTTON_PUBLISH_0, 322 buttonStyle); 323 } else { 324 return ""; 325 } 326 } 327 328 if (getCms().isManagerOfProject()) { 329 return (button( 330 "../../workplace/commons/publish_project.jsp", 331 "body", 332 "publish.png", 333 Messages.GUI_BUTTON_PUBLISH_0, 334 buttonStyle)); 335 } else { 336 return (button(null, null, "publish_in.png", Messages.GUI_BUTTON_PUBLISH_0, buttonStyle)); 337 } 338 } 339 340 /** 341 * Returns the html for the "publish queue" button.<p> 342 * 343 * @return the html for the "publish queue" button 344 */ 345 public String getPublishQueueButton() { 346 347 int buttonStyle = getSettings().getUserSettings().getWorkplaceButtonStyle(); 348 StringBuffer js = new StringBuffer(128); 349 js.append("javascript:if (parent.body.admin_content && parent.body.admin_menu) {"); 350 js.append("parent.body.location.href = '"); 351 js.append(getJsp().link("/system/workplace/views/admin/admin-fs.jsp?root=admin&path=/publishqueue")); 352 js.append("';"); 353 js.append("} else {"); 354 js.append("parent.body.explorer_body.explorer_files.location.href = '"); 355 js.append(getJsp().link("/system/workplace/views/admin/admin-fs.jsp?root=explorer&path=/publishqueue&menu=no")); 356 js.append("';"); 357 js.append("};"); 358 return button(js.toString(), null, "publish_queue.png", Messages.GUI_BUTTON_PUBLISHQUEUE_0, buttonStyle); 359 } 360 361 /** 362 * Returns a html select box filled with the current users accessible sites.<p> 363 * 364 * @param htmlAttributes attributes that will be inserted into the generated html 365 * @return a html select box filled with the current users accessible sites 366 */ 367 public String getSiteSelect(String htmlAttributes) { 368 369 List<String> options = new ArrayList<String>(); 370 List<String> values = new ArrayList<String>(); 371 int selectedIndex = 0; 372 373 List<CmsSite> sites = OpenCms.getSiteManager().getAvailableSites(getCms(), true); 374 375 Iterator<CmsSite> i = sites.iterator(); 376 int pos = 0; 377 while (i.hasNext()) { 378 CmsSite site = i.next(); 379 values.add(site.getSiteRoot()); 380 options.add(substituteSiteTitle(site.getTitle())); 381 String siteRoot = CmsFileUtil.addTrailingSeparator(site.getSiteRoot()); 382 String settingsSiteRoot = getSettings().getSite(); 383 if (settingsSiteRoot != null) { 384 settingsSiteRoot = CmsFileUtil.addTrailingSeparator(settingsSiteRoot); 385 } 386 if (siteRoot.equals(settingsSiteRoot)) { 387 // this is the user's current site 388 selectedIndex = pos; 389 } 390 pos++; 391 } 392 393 return buildSelect(htmlAttributes, options, values, selectedIndex); 394 } 395 396 /** 397 * Returns the startup URI for display in the main body frame, this can 398 * either be the user default view, or (if set) a specific startup resource.<p> 399 * 400 * @return the startup URI for display in the main body frame 401 */ 402 public String getStartupUri() { 403 404 String result = getSettings().getViewStartup(); 405 if (result == null) { 406 // no specific startup URI is set, use view from user settings 407 result = getSettings().getViewUri(); 408 } else { 409 // reset the startup URI, so that it is not displayed again on reload of the frameset 410 getSettings().setViewStartup(null); 411 } 412 // add eventual request parameters to startup uri 413 if (getJsp().getRequest().getParameterMap().size() > 0) { 414 @SuppressWarnings("unchecked") 415 Set<Entry<String, String[]>> params = getJsp().getRequest().getParameterMap().entrySet(); 416 Iterator<Entry<String, String[]>> i = params.iterator(); 417 while (i.hasNext()) { 418 Entry<?, ?> entry = i.next(); 419 result = CmsRequestUtil.appendParameter( 420 result, 421 (String)entry.getKey(), 422 ((String[])entry.getValue())[0]); 423 } 424 } 425 // append the frame name to the startup uri 426 return CmsRequestUtil.appendParameter(result, CmsFrameset.PARAM_WP_FRAME, FRAMES[2]); 427 } 428 429 /** 430 * Returns a html select box filled with the views accessible by the current user.<p> 431 * 432 * @param htmlAttributes attributes that will be inserted into the generated html 433 * @return a html select box filled with the views accessible by the current user 434 */ 435 public String getViewSelect(String htmlAttributes) { 436 437 List<String> options = new ArrayList<String>(); 438 List<String> values = new ArrayList<String>(); 439 int selectedIndex = 0; 440 441 // loop through the vectors and fill the result vectors 442 Iterator<CmsWorkplaceView> i = OpenCms.getWorkplaceManager().getViews().iterator(); 443 int count = -1; 444 String currentView = getSettings().getViewUri(); 445 if (CmsStringUtil.isNotEmpty(currentView)) { 446 // remove possible parameters from current view 447 int pos = currentView.indexOf('?'); 448 if (pos >= 0) { 449 currentView = currentView.substring(0, pos); 450 } 451 } 452 while (i.hasNext()) { 453 CmsWorkplaceView view = i.next(); 454 if (getCms().existsResource(view.getUri(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) { 455 count++; 456 // ensure the current user has +v+r permissions on the view 457 String loopLink = getJsp().link(view.getUri()); 458 String localizedKey = resolveMacros(view.getKey()); 459 options.add(localizedKey); 460 values.add(loopLink); 461 462 if (loopLink.equals(currentView)) { 463 selectedIndex = count; 464 } 465 } 466 } 467 468 return buildSelect(htmlAttributes, options, values, selectedIndex); 469 } 470 471 /** 472 * Returns the reload URI for the OpenCms workplace.<p> 473 * 474 * @return the reload URI for the OpenCms workplace 475 */ 476 public String getWorkplaceReloadUri() { 477 478 return getJsp().link(CmsFrameset.JSP_WORKPLACE_URI); 479 } 480 481 /** 482 * Returns <code>true</code> if a reload of the main body frame is required.<p> 483 * 484 * This value is modified with the select options (project, site or view) in the head frame of 485 * the Workplace. If a user changes one of these select values, the head frame is posted 486 * "against itself". The posted values will be processed by this class, causing 487 * the internal Workplace settings to change. After these settings have been changed, 488 * a reload of the main body frame is required in order to update it with the new values. 489 * A JavaScript in the Workplace head frame will be executed in this case.<p> 490 * 491 * @return <code>true</code> if a reload of the main body frame is required 492 */ 493 public boolean isReloadRequired() { 494 495 return m_reloadRequired; 496 } 497 498 /** 499 * Returns true if the user has enabled synchronization.<p> 500 * 501 * @return true if the user has enabled synchronization 502 */ 503 public boolean isSyncEnabled() { 504 505 CmsSynchronizeSettings syncSettings = getSettings().getUserSettings().getSynchronizeSettings(); 506 return (syncSettings != null) && syncSettings.isSyncEnabled(); 507 } 508 509 /** 510 * Indicates if the site selector should be shown in the top frame depending on the count of accessible sites.<p> 511 * 512 * @return true if site selector should be shown, otherwise false 513 */ 514 public boolean showSiteSelector() { 515 516 if (getSettings().getUserSettings().getRestrictExplorerView()) { 517 // restricted explorer view to site and folder, do not show site selector 518 return false; 519 } 520 // count available sites 521 int siteCount = OpenCms.getSiteManager().getAvailableSites(getCms(), true).size(); 522 return (siteCount > 1); 523 } 524 525 /** 526 * @see org.opencms.workplace.CmsWorkplace#initTimeWarp(org.opencms.db.CmsUserSettings, javax.servlet.http.HttpSession) 527 */ 528 @Override 529 protected void initTimeWarp(CmsUserSettings settings, HttpSession session) { 530 531 // overriden to avoid deletion of the configured time warp: 532 // this is triggered by editors and in auto time warping a direct edit 533 // must not delete a potential auto warped request time 534 } 535 536 /** 537 * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest) 538 */ 539 @Override 540 protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) { 541 542 // check if a startup page has been set 543 String frame = CmsRequestUtil.getNotEmptyDecodedParameter(request, CmsFrameset.PARAM_WP_FRAME); 544 if ((frame == null) || (FRAMES_LIST.indexOf(frame) < 0)) { 545 // illegal or no frame selected, assume the "top" frame 546 frame = FRAMES[0]; 547 } 548 549 if (FRAMES[0].equals(frame)) { 550 // top frame requested - execute special reload actions 551 topFrameReload(settings); 552 } 553 554 // check if a startup page has been set 555 String startup = CmsRequestUtil.getNotEmptyDecodedParameter(request, CmsFrameset.PARAM_WP_START); 556 if (startup != null) { 557 m_reloadRequired = true; 558 settings.setViewStartup(startup); 559 } 560 561 // check if the user requested a view change 562 String view = request.getParameter(CmsFrameset.PARAM_WP_VIEW); 563 if (view != null) { 564 m_reloadRequired = true; 565 settings.setViewUri(view); 566 settings.getFrameUris().put("body", view); 567 } 568 569 m_reloadRequired = initSettings(settings, request) || m_reloadRequired; 570 } 571 572 /** 573 * Performs certain clear cache actions if the top frame is reloaded.<p> 574 * 575 * @param settings the current users workplace settings 576 */ 577 protected void topFrameReload(CmsWorkplaceSettings settings) { 578 579 // ensure to read the settings from the database 580 initUserSettings(getCms(), settings, true); 581 582 // reset the HTML list in order to force a full reload 583 settings.setListObject(null); 584 } 585}