001: /*
002: * Copyright (C) 2006 Methodhead Software LLC. All rights reserved.
003: *
004: * This file is part of TransferCM.
005: *
006: * TransferCM is free software; you can redistribute it and/or modify it under the
007: * terms of the GNU General Public License as published by the Free Software
008: * Foundation; either version 2 of the License, or (at your option) any later
009: * version.
010: *
011: * TransferCM is distributed in the hope that it will be useful, but WITHOUT ANY
012: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
013: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
014: * details.
015: *
016: * You should have received a copy of the GNU General Public License along with
017: * TransferCM; if not, write to the Free Software Foundation, Inc., 51 Franklin St,
018: * Fifth Floor, Boston, MA 02110-1301 USA
019: */
020:
021: package com.methodhead.shim;
022:
023: import java.util.HashMap;
024: import java.util.List;
025: import java.util.Map;
026: import java.io.IOException;
027:
028: import com.methodhead.persistable.Persistable;
029: import com.methodhead.persistable.PersistableException;
030:
031: import org.apache.commons.beanutils.DynaClass;
032: import org.apache.commons.beanutils.DynaProperty;
033: import org.apache.commons.beanutils.BasicDynaClass;
034: import javax.servlet.http.HttpServletRequest;
035: import javax.servlet.http.HttpServletResponse;
036: import javax.servlet.jsp.JspWriter;
037: import org.apache.struts.action.ActionMapping;
038: import org.apache.struts.action.DynaActionForm;
039: import org.apache.struts.action.ActionForward;
040: import javax.servlet.RequestDispatcher;
041: import javax.servlet.ServletException;
042: import com.methodhead.sitecontext.SiteContext;
043: import org.apache.commons.lang.StringUtils;
044: import org.apache.commons.lang.exception.ExceptionUtils;
045:
046: /**
047: * A NavModule. The following fields are defined:
048: * <ul>
049: * <li><tt>int sitecontext_id = 0</tt></li>
050: * <li><tt>String template = ""</tt></li>
051: * <li><tt>String panel = ""</tt></li>
052: * <li><tt>Boolean hideroot = false</tt></li>
053: * <li><tt>String type = ""</tt></li>
054: * <li><tt>String separator = ""</tt></li>
055: * <li><tt>String jsp = ""</tt></li>
056: * <li><tt>Integer startlev = 1</tt></li>
057: * <li><tt>Integer contextlev = 1</tt></li>
058: * <li><tt>Integer depthlev = 1</tt></li>
059: * <li><tt>Integer toplev = 1</tt></li>
060: * <li><tt>String header = ""</tt></li>
061: * <li><tt>String link = ""</tt></li>
062: * <li><tt>String curlink = ""</tt></li>
063: * <li><tt>String footer = ""</tt></li>
064: * </ul>
065: */
066: public class NavModule extends Persistable implements Module {
067:
068: protected static DynaClass dynaClass_ = null;
069:
070: static {
071: DynaProperty[] dynaProperties = new DynaProperty[] {
072: new DynaProperty("sitecontext_id", Integer.class),
073: new DynaProperty("template", String.class),
074: new DynaProperty("panel", String.class),
075: new DynaProperty("hideroot", Boolean.class),
076: new DynaProperty("type", String.class),
077: new DynaProperty("separator", String.class),
078: new DynaProperty("jsp", String.class),
079: new DynaProperty("startlev", Integer.class),
080: new DynaProperty("contextlev", Integer.class),
081: new DynaProperty("depthlev", Integer.class),
082: new DynaProperty("toplev", Integer.class),
083: new DynaProperty("header", String.class),
084: new DynaProperty("link", String.class),
085: new DynaProperty("curlink", String.class),
086: new DynaProperty("footer", String.class) };
087:
088: dynaClass_ = new BasicDynaClass("shim_nav", NavModule.class,
089: dynaProperties);
090: }
091:
092: // constructors /////////////////////////////////////////////////////////////
093:
094: public NavModule() {
095: super (dynaClass_);
096: init();
097: }
098:
099: public NavModule(DynaClass dynaClass) {
100: super (dynaClass);
101: init();
102: }
103:
104: // constants ////////////////////////////////////////////////////////////////
105:
106: public static final String TYPE_TEXTSEPARATED = "TEXTSEPARATED";
107: public static final String TYPE_JSP = "JSP";
108: public static final String TYPE_FOLDING = "FOLDING";
109:
110: public static final String DEFAULT_TYPE = TYPE_TEXTSEPARATED;
111: public static final String DEFAULT_SEPARATOR = " | ";
112:
113: // classes //////////////////////////////////////////////////////////////////
114:
115: // methods //////////////////////////////////////////////////////////////////
116:
117: private void init() {
118: setInt("sitecontext_id", 0);
119: setString("template", "");
120: setString("panel", "");
121: setBoolean("hideroot", false);
122: setString("type", "");
123: setString("separator", "");
124: setString("jsp", "");
125: setInt("startlev", 1);
126: setInt("contextlev", 1);
127: setInt("depthlev", 1);
128: setInt("toplev", 1);
129: setString("header", "");
130: setString("link", "");
131: setString("curlink", "");
132: setString("footer", "");
133: }
134:
135: /**
136: * Loads the nav for the site context, template, and panel set up when init
137: * is called.
138: */
139: public void load() {
140: load("sitecontext_id=" + getInt("sitecontext_id")
141: + " AND template="
142: + getSqlLiteral(getString("template")) + " AND panel="
143: + getSqlLiteral(getString("panel")));
144: }
145:
146: /**
147: * Saves the nav for the site context, template, and panel set up when init
148: * is called; be sure the module is created first.
149: */
150: public void save() {
151: save("sitecontext_id=" + getInt("sitecontext_id")
152: + " AND template="
153: + getSqlLiteral(getString("template")) + " AND panel="
154: + getSqlLiteral(getString("panel")));
155: }
156:
157: public String getName() {
158: return "Navigation";
159: }
160:
161: public void init(Page page, String panel) {
162:
163: setInt("sitecontext_id", page.getSiteContext().getInt("id"));
164: setString("template", page.getString("template"));
165: setString("panel", panel);
166:
167: //
168: // we'll need this for getLinkUrl()
169: //
170: siteContextPath_ = page.getSiteContext().getString("path");
171: }
172:
173: public void create() {
174: //
175: // does the nav already exist?
176: //
177: try {
178: load();
179: } catch (PersistableException e) {
180: //
181: // create the nav
182: //
183: setString("type", DEFAULT_TYPE);
184: setString("separator", DEFAULT_SEPARATOR);
185: saveNew();
186: }
187: }
188:
189: public void destroy() {
190: //
191: // do nothing; we actually just let nav's pile up for now
192: //
193: }
194:
195: /**
196: * Renders a link in a text-separated nav. <tt>link</tt> and
197: * <tt>curlink</tt> are used if they are set, otherwise a plain hyperlink is
198: * renedered.
199: */
200: protected void renderTextSeparatedLink(JspWriter out, Link link,
201: Link cur, boolean isEditMode) throws IOException {
202:
203: String s = null;
204:
205: if (link.isRoot()) {
206: if (cur == link)
207: s = getString("curlink");
208: else
209: s = getString("link");
210: } else {
211: if (cur.isNodeAncestor(link))
212: s = getString("curlink");
213: else
214: s = getString("link");
215: }
216:
217: String url = ShimUtils.getLinkUrl(link);
218:
219: if ("".equals(s)) {
220: out.print("<a href=\"" + url + "\">" + link.getTitle()
221: + "</a>");
222: } else {
223: s = StringUtils.replace(s, FoldingNavRenderer.URL_KEY, url);
224: s = StringUtils.replace(s, FoldingNavRenderer.TITLE_KEY,
225: link.getTitle());
226: }
227:
228: out.print(s);
229: }
230:
231: public void display(HttpServletRequest request,
232: HttpServletResponse response, JspWriter out)
233: throws IOException {
234:
235: //
236: // load the nav
237: //
238: load();
239:
240: //
241: // get things we'll need
242: //
243: Page curPage = (Page) request
244: .getAttribute(ShimGlobals.PAGE_KEY);
245: SiteMap siteMap = ShimUtils.getSiteMap(request);
246: Link root = (Link) siteMap.getRoot();
247: Link cur = siteMap.find(curPage.getInt("id"));
248: boolean isEditMode = ShimGlobals.MODE_EDIT.equals(request
249: .getSession().getAttribute(ShimGlobals.MODE_KEY));
250:
251: //
252: // text separated
253: //
254: if (TYPE_TEXTSEPARATED.equals(getString("type"))) {
255: try {
256: if (root != null) {
257:
258: out.print(getString("header"));
259:
260: //
261: // remember when we display a link, that way we'll know we have to
262: // display a separator
263: //
264: boolean linkRendered = false;
265:
266: //
267: // render root link
268: //
269: if (!getBoolean("hideroot") && !root.getHidden()) {
270: renderTextSeparatedLink(out, root, cur,
271: isEditMode);
272: linkRendered = true;
273: }
274:
275: //
276: // render the top-level links
277: //
278: for (int i = 0; i < root.getChildCount(); i++) {
279: Link link = (Link) root.getChildAt(i);
280:
281: if (!link.getHidden()) {
282:
283: if (linkRendered) {
284: out.print(getString("separator"));
285: }
286:
287: renderTextSeparatedLink(out, link, cur,
288: isEditMode);
289: linkRendered = true;
290: }
291: }
292:
293: out.print(getString("footer"));
294: }
295: } catch (IOException e) {
296: throw new ShimException(
297: "Unexpected IOException while printing nav.");
298: }
299: }
300:
301: //
302: // jsp
303: //
304: else if (TYPE_JSP.equals(getString("type"))) {
305: try {
306: //
307: // put the current link into the request
308: //
309: request.setAttribute(ShimGlobals.CURRENTLINK_KEY, cur);
310:
311: //
312: // include the jsp
313: //
314: SiteContext siteContext = SiteContext
315: .getContext(request);
316:
317: out.flush();
318:
319: RequestDispatcher dispatcher = request.getSession()
320: .getServletContext().getRequestDispatcher(
321: "/WEB-INF/resources/"
322: + siteContext.getInt("id")
323: + "/" + getString("jsp"));
324:
325: dispatcher.include(request, response);
326: } catch (ServletException e) {
327: out.println(ExceptionUtils.getStackTrace(e));
328: }
329: }
330:
331: //
332: // folding
333: //
334: else if (TYPE_FOLDING.equals(getString("type"))) {
335: try {
336: FoldingNavRenderer renderer = new FoldingNavRenderer();
337: renderer.setRoot(root);
338: renderer.setCur(cur);
339: renderer.setStart(getInt("startlev"));
340: renderer.setContext(getInt("contextlev"));
341: renderer.setDepth(getInt("depthlev"));
342: renderer.setTop(getInt("toplev"));
343: renderer.setHeader(getString("header"));
344: renderer.setLink(getString("link"));
345: renderer.setCurLink(getString("curlink"));
346: renderer.setFooter(getString("footer"));
347: renderer.setIsEditMode(ShimGlobals.MODE_EDIT
348: .equals(request.getSession().getAttribute(
349: ShimGlobals.MODE_KEY)));
350:
351: out.println(renderer.getNavHtml());
352: } catch (IOException e) {
353: throw new ShimException(
354: "Unexpected IOException while printing nav.");
355: }
356: } else {
357: throw new ShimException("Unexpected nav type \""
358: + getString("type") + "\".");
359: }
360: }
361:
362: public boolean isConfigurable() {
363: return true;
364: }
365:
366: public ActionForward configure(ActionMapping mapping,
367: DynaActionForm form, HttpServletRequest request,
368: HttpServletResponse response) {
369:
370: return new ActionForward("/configureNavModuleForm.do?pageid="
371: + form.get("pageid") + "&panel=" + form.get("panel"));
372: }
373:
374: public boolean isEditable() {
375: return false;
376: }
377:
378: /**
379: * Not implemented.
380: */
381: public void update(String text) {
382: }
383:
384: public void copyTo(Page page) {
385: //
386: // nav modules don't store page-specific data (only
387: // template/sitecontext-specific), so since this nav module already exists,
388: // we don't have to do anything
389: //
390: }
391:
392: // properties ///////////////////////////////////////////////////////////////
393:
394: // attributes ///////////////////////////////////////////////////////////////
395:
396: private String siteContextPath_ = null;
397: }
|