001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/content/tags/sakai_2-4-1/content-tool/tool/src/java/org/sakaiproject/content/tool/AttachmentAction.java $
003: * $Id: AttachmentAction.java 7514 2006-04-09 13:00:43Z ggolden@umich.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.content.tool;
021:
022: import java.util.Collections;
023: import java.util.List;
024: import java.util.Vector;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028: import org.sakaiproject.cheftool.Context;
029: import org.sakaiproject.cheftool.JetspeedRunData;
030: import org.sakaiproject.cheftool.RunData;
031: import org.sakaiproject.cheftool.VelocityPortlet;
032: import org.sakaiproject.cheftool.VelocityPortletPaneledAction;
033: import org.sakaiproject.cheftool.api.Menu;
034: import org.sakaiproject.cheftool.api.MenuItem;
035: import org.sakaiproject.cheftool.menu.MenuEntry;
036: import org.sakaiproject.cheftool.menu.MenuImpl;
037: import org.sakaiproject.component.cover.ServerConfigurationService;
038: import org.sakaiproject.content.api.ContentCollection;
039: import org.sakaiproject.content.api.ContentResource;
040: import org.sakaiproject.content.cover.ContentHostingService;
041: import org.sakaiproject.content.cover.ContentTypeImageService;
042: import org.sakaiproject.entity.api.Reference;
043: import org.sakaiproject.entity.api.ResourceProperties;
044: import org.sakaiproject.entity.api.ResourcePropertiesEdit;
045: import org.sakaiproject.entity.cover.EntityManager;
046: import org.sakaiproject.event.api.SessionState;
047: import org.sakaiproject.site.cover.SiteService;
048: import org.sakaiproject.util.FileItem;
049: import org.sakaiproject.util.ResourceLoader;
050: import org.sakaiproject.util.StringUtil;
051: import org.sakaiproject.util.Validator;
052: import org.sakaiproject.tool.cover.ToolManager;
053:
054: /**
055: * <p>
056: * AttachmentAction is a helper Action that other tools can use to edit their attachments.
057: * </p>
058: */
059: public class AttachmentAction {
060: /** Our logger. */
061: private static Log M_log = LogFactory
062: .getLog(AttachmentAction.class);
063:
064: /** Resource bundle using current language locale */
065: private static ResourceLoader rb = new ResourceLoader("helper");
066:
067: /** State attributes for Attachments mode - when it's MODE_DONE the tool can process the results. */
068: public static final String STATE_MODE = "attachment.mode";
069:
070: /** State attribute for where there is at least one attachment before invoking attachment tool */
071: public static final String STATE_HAS_ATTACHMENT_BEFORE = "attachment.has_attachment_before";
072:
073: /**
074: * State attribute for the Vector of References, one for each attachment. Using tools can pre-populate, and can read the results from here.
075: */
076: public static final String STATE_ATTACHMENTS = "attachment.attachments";
077:
078: /** The part of the message after "Attachments for:", set by the client tool. */
079: public static final String STATE_FROM_TEXT = "attachment.from_text";
080:
081: /** State attributes for private use. */
082: private static final String STATE_ATTACHMENT = "attachment.attachment";
083:
084: /** The collection id being browsed. */
085: private static final String STATE_BROWSE_COLLECTION_ID = "attachment.collection_id";
086:
087: /** The id of the "home" collection (can't go up from here. */
088: private static final String STATE_HOME_COLLECTION_ID = "attachment.collection_home";
089:
090: /** Modes. */
091: public static final String MODE_DONE = "done";
092:
093: public static final String MODE_MAIN = "main";
094:
095: private static final String MODE_BROWSE = "browse";
096:
097: private static final String MODE_PROPERTIES = "props";
098:
099: private static final String MODE_UPLOAD = "upload";
100:
101: private static final String MODE_URL = "url";
102:
103: // TODO: path too hard coded
104: /** vm files for each mode. */
105: private static final String TEMPLATE_MAIN = "helper/chef_attachment_main";
106:
107: private static final String TEMPLATE_BROWSE = "helper/chef_attachment_browse";
108:
109: private static final String TEMPLATE_PROPERTIES = "/helper/chef_attachment_properties";
110:
111: private static final String TEMPLATE_UPLOAD = "helper/chef_attachment_upload";
112:
113: private static final String TEMPLATE_URL = "helper/chef_attachment_url";
114:
115: /** the DEFAULT maximun size for file upload */
116: private static final String FILE_UPLOAD_MAX_SIZE = "file_upload_max_size";
117:
118: /**
119: * build the context.
120: *
121: * @return The name of the template to use.
122: */
123: static public String buildHelperContext(VelocityPortlet portlet,
124: Context context, RunData rundata, SessionState state) {
125: // look for a failed upload, which leaves the /special/upload in the URL %%%
126: if (StringUtil.trimToNull(rundata.getParameters().getString(
127: "special")) != null) {
128: VelocityPortletPaneledAction.addAlert(state, rb
129: .getString("theupsiz")
130: + " "
131: + state.getAttribute(FILE_UPLOAD_MAX_SIZE)
132: + "MB " + rb.getString("hasbeeexc"));
133: }
134:
135: if (state.getAttribute(FILE_UPLOAD_MAX_SIZE) == null) {
136: state.setAttribute(FILE_UPLOAD_MAX_SIZE,
137: ServerConfigurationService.getString(
138: "content.upload.max", "1"));
139: }
140:
141: // make sure we have attachments
142: List attachments = (List) state.getAttribute(STATE_ATTACHMENTS);
143: if (attachments == null) {
144: attachments = EntityManager.newReferenceList();
145: state.setAttribute(STATE_ATTACHMENTS, attachments);
146: }
147:
148: // make sure we have a from text to display
149: if (state.getAttribute(STATE_FROM_TEXT) == null) {
150: state.setAttribute(STATE_FROM_TEXT, "");
151: }
152:
153: // set me as the helper class
154: state.setAttribute(VelocityPortletPaneledAction.STATE_HELPER,
155: AttachmentAction.class.getName());
156:
157: // set the "from" message
158: context.put("from", rb.getString("attfor") + " "
159: + state.getAttribute(STATE_FROM_TEXT));
160:
161: // get the mode
162: String mode = (String) state.getAttribute(STATE_MODE);
163: if (mode == null)
164: mode = MODE_MAIN;
165:
166: if (mode.equals(MODE_MAIN)) {
167: return buildMainContext(portlet, context, rundata, state);
168: } else if (mode.equals(MODE_BROWSE)) {
169: return buildBrowseContext(portlet, context, rundata, state);
170: } else if (mode.equals(MODE_PROPERTIES)) {
171: return buildPropertiesContext(portlet, context, rundata,
172: state);
173: } else if (mode.equals(MODE_UPLOAD)) {
174: return buildUploadContext(portlet, context, rundata, state);
175: } else if (mode.equals(MODE_URL)) {
176: return buildUrlContext(portlet, context, rundata, state);
177: } else {
178: // %%%
179: }
180:
181: return null;
182:
183: } // buildHelperContext
184:
185: /**
186: * build the context for the main display
187: *
188: * @return The name of the template to use.
189: */
190: static public String buildMainContext(VelocityPortlet portlet,
191: Context context, RunData rundata, SessionState state) {
192: // place the attribute vector (of References) into the context
193: List attachments = (List) state.getAttribute(STATE_ATTACHMENTS);
194: context.put("thelp", rb);
195: context.put("attachments", attachments);
196:
197: // make the content type image service available
198: context.put("contentTypeImageService", ContentTypeImageService
199: .getInstance());
200:
201: // the menu
202: buildMenu(portlet, context, rundata, state, true, (attachments
203: .size() > 0));
204:
205: // for toolbar
206: context.put("enabled", new Boolean(true));
207: context.put("anyattachment",
208: new Boolean(attachments.size() > 0));
209: context.put("has_attachment_before", state
210: .getAttribute(STATE_HAS_ATTACHMENT_BEFORE));
211:
212: return TEMPLATE_MAIN;
213:
214: } // buildMainContext
215:
216: /**
217: * build the context for the browsing for resources display
218: *
219: * @return The name of the template to use.
220: */
221: static public String buildBrowseContext(VelocityPortlet portlet,
222: Context context, RunData rundata, SessionState state) {
223: context.put("thelp", rb);
224: // make sure the channedId is set
225: String id = (String) state
226: .getAttribute(STATE_BROWSE_COLLECTION_ID);
227: if (id == null) {
228: id = ContentHostingService.getSiteCollection(ToolManager
229: .getCurrentPlacement().getContext());
230: state.setAttribute(STATE_BROWSE_COLLECTION_ID, id);
231: state.setAttribute(STATE_HOME_COLLECTION_ID, id);
232: }
233:
234: context.put("contentHostingService", ContentHostingService
235: .getInstance());
236:
237: String collectionDisplayName = null;
238: List members = null;
239:
240: try {
241: // get this collection's display name
242: ContentCollection collection = ContentHostingService
243: .getCollection(id);
244: collectionDisplayName = collection.getProperties()
245: .getPropertyFormatted(
246: ResourceProperties.PROP_DISPLAY_NAME);
247:
248: // get the full set of member objects
249: members = collection.getMemberResources();
250:
251: // sort by display name, ascending
252: Collections
253: .sort(
254: members,
255: ContentHostingService
256: .newContentHostingComparator(
257: ResourceProperties.PROP_DISPLAY_NAME,
258: true));
259: } catch (Exception e) {
260: collectionDisplayName = SiteService
261: .getSiteDisplay(ToolManager.getCurrentPlacement()
262: .getContext());
263: members = new Vector();
264: }
265:
266: context.put("collectionDisplayName", collectionDisplayName);
267: context.put("collectionMembers", members);
268: context.put("includeUp", new Boolean(!id.equals(state
269: .getAttribute(STATE_HOME_COLLECTION_ID))));
270:
271: // place the attribute vector (of References) into the context
272: context.put("attachments", state
273: .getAttribute(STATE_ATTACHMENTS));
274:
275: // make the content type image service available
276: context.put("contentTypeImageService", ContentTypeImageService
277: .getInstance());
278:
279: // the menu
280: buildMenu(portlet, context, rundata, state, false, false);
281: context.put("enabled", new Boolean(false));
282: context.put("anyattachment", new Boolean(false));
283:
284: return TEMPLATE_BROWSE;
285:
286: } // buildBrowseContext
287:
288: /**
289: * build the context for the upload display
290: *
291: * @return The name of the template to use.
292: */
293: static public String buildUploadContext(VelocityPortlet portlet,
294: Context context, RunData rundata, SessionState state) {
295: context.put("thelp", rb);
296: // the menu
297: buildMenu(portlet, context, rundata, state, false, false);
298: // for toolbar
299: context.put("enabled", new Boolean(false));
300: context.put("anyattachment", new Boolean(false));
301:
302: return TEMPLATE_UPLOAD;
303:
304: } // buildUploadContext
305:
306: /**
307: * build the context for the url display
308: *
309: * @return The name of the template to use.
310: */
311: static public String buildUrlContext(VelocityPortlet portlet,
312: Context context, RunData rundata, SessionState state) {
313: context.put("thelp", rb);
314: // the menu
315: buildMenu(portlet, context, rundata, state, false, false);
316: // for toolbar
317: context.put("enabled", new Boolean(false));
318: context.put("anyattachment", new Boolean(false));
319:
320: return TEMPLATE_URL;
321:
322: } // buildUrlContext
323:
324: /**
325: * Build the menu.
326: */
327: private static void buildMenu(VelocityPortlet portlet,
328: Context context, RunData rundata, SessionState state,
329: boolean enabled, boolean anyAttachments) {
330: Menu bar = new MenuImpl(portlet, rundata, "AttachmentAction");
331: String formName = "mainForm";
332:
333: bar.add(new MenuEntry(rb.getString("locfil"), null, enabled,
334: MenuItem.CHECKED_NA, "doUpload", formName));
335: bar.add(new MenuEntry(rb.getString("weburl"), null, enabled,
336: MenuItem.CHECKED_NA, "doUrl", formName));
337: bar.add(new MenuEntry(rb.getString("frores"), null, enabled,
338: MenuItem.CHECKED_NA, "doBrowse", formName));
339: bar.add(new MenuEntry(rb.getString("remsel"), null, enabled
340: && anyAttachments, MenuItem.CHECKED_NA, "doRemove",
341: formName));
342: bar.add(new MenuEntry(rb.getString("remall"), null, enabled
343: && anyAttachments, MenuItem.CHECKED_NA, "doRemove_all",
344: formName));
345:
346: context.put(Menu.CONTEXT_MENU, bar);
347: context.put(Menu.CONTEXT_ACTION, "AttachmentAction");
348: state.setAttribute(MenuItem.STATE_MENU, bar);
349:
350: } // buildMenu
351:
352: /**
353: * build the context for the properties editing for attachment display
354: *
355: * @return The name of the template to use.
356: */
357: static public String buildPropertiesContext(
358: VelocityPortlet portlet, Context context, RunData rundata,
359: SessionState state) {
360: // %%% more context setup
361: context.put("thelp", rb);
362: // put in the single Reference for the selected attachment
363: context.put("attachment", state.getAttribute(STATE_ATTACHMENT));
364:
365: return TEMPLATE_PROPERTIES;
366:
367: } // buildPropertiesContext
368:
369: /**
370: * Remove the state variables used internally, on the way out.
371: */
372: static private void cleanupState(SessionState state) {
373: state.removeAttribute(STATE_ATTACHMENT);
374: state.removeAttribute(STATE_BROWSE_COLLECTION_ID);
375: state.removeAttribute(STATE_HOME_COLLECTION_ID);
376: state.removeAttribute(STATE_FROM_TEXT);
377: state.removeAttribute(STATE_HAS_ATTACHMENT_BEFORE);
378: state
379: .removeAttribute(VelocityPortletPaneledAction.STATE_HELPER);
380:
381: } // cleanupState
382:
383: /**
384: * Handle the eventSubmit_doSave command to save the edited attachments.
385: */
386: static public void doSave(RunData data) {
387: SessionState state = ((JetspeedRunData) data)
388: .getPortletSessionState(((JetspeedRunData) data)
389: .getJs_peid());
390: // end up in done mode
391: state.setAttribute(STATE_MODE, MODE_DONE);
392:
393: // clean up state
394: cleanupState(state);
395:
396: } // doSave
397:
398: /**
399: * Handle the eventSubmit_doCancel command to abort the edits.
400: */
401: static public void doCancel(RunData data) {
402: SessionState state = ((JetspeedRunData) data)
403: .getPortletSessionState(((JetspeedRunData) data)
404: .getJs_peid());
405:
406: // end up in done mode
407: state.setAttribute(STATE_MODE, MODE_DONE);
408:
409: // remove the attachments from the state to indicate that cancel was done
410: state.removeAttribute(STATE_ATTACHMENTS);
411:
412: // clean up state
413: cleanupState(state);
414:
415: } // doCancel
416:
417: /**
418: * Handle the eventSubmit_doBrowse command to go into browse for a resource on the site mode.
419: */
420: static public void doBrowse(RunData data) {
421: SessionState state = ((JetspeedRunData) data)
422: .getPortletSessionState(((JetspeedRunData) data)
423: .getJs_peid());
424:
425: // end up in browse mode
426: state.setAttribute(STATE_MODE, MODE_BROWSE);
427:
428: } // doBrowse
429:
430: /**
431: * Handle the eventSubmit_doUpload command to go into upload resource mode.
432: */
433: static public void doUpload(RunData data) {
434: SessionState state = ((JetspeedRunData) data)
435: .getPortletSessionState(((JetspeedRunData) data)
436: .getJs_peid());
437:
438: // end up in upload mode
439: state.setAttribute(STATE_MODE, MODE_UPLOAD);
440:
441: } // doUpload
442:
443: /**
444: * Handle the eventSubmit_doUrl command to go into enter url mode.
445: */
446: static public void doUrl(RunData data) {
447: SessionState state = ((JetspeedRunData) data)
448: .getPortletSessionState(((JetspeedRunData) data)
449: .getJs_peid());
450:
451: // end up in url mode
452: state.setAttribute(STATE_MODE, MODE_URL);
453:
454: } // doUrl
455:
456: /**
457: * Handle the eventSubmit_doAdd command to add attachments.
458: */
459: static public void doAdd(RunData data) {
460: SessionState state = ((JetspeedRunData) data)
461: .getPortletSessionState(((JetspeedRunData) data)
462: .getJs_peid());
463:
464: // add to the attachments vector
465: Vector attachments = (Vector) state
466: .getAttribute(STATE_ATTACHMENTS);
467:
468: // see if the user entered a url to add
469: String url = data.getParameters().getString("url");
470: if (url != null)
471: url = url.trim();
472: if ((url != null) && (url.length() > 0)) {
473: // if it's missing the transport, add http://
474: if (url.indexOf("://") == -1)
475: url = "http://" + url;
476:
477: // make a set of properties to add for the new resource
478: ResourcePropertiesEdit props = ContentHostingService
479: .newResourceProperties();
480: props
481: .addProperty(ResourceProperties.PROP_DISPLAY_NAME,
482: url);
483: props.addProperty(ResourceProperties.PROP_DESCRIPTION, url);
484:
485: // make an attachment resource for this URL
486: try {
487: ContentResource attachment = ContentHostingService
488: .addAttachmentResource(Validator
489: .escapeResourceName(url), // use the url as the name
490: ResourceProperties.TYPE_URL, url
491: .getBytes(), props);
492:
493: // add a dereferencer for this to the attachments
494: attachments.add(EntityManager.newReference(attachment
495: .getReference()));
496: } catch (Exception any) {
497: M_log
498: .warn("AttachmentAction"
499: + ".doAdd: exception adding attachment resource (urlName: "
500: + Validator.escapeResourceName(url)
501: + "): " + any.toString());
502: }
503:
504: } // if ((url != null) && (url.length() > 0))
505:
506: // see if the user uploaded a file
507: FileItem file = data.getParameters().getFileItem("file");
508: if (file != null) {
509: // the file content byte[]
510: byte[] in = file.get();
511:
512: // the content type
513: String contentType = file.getContentType();
514:
515: // the file name - as reported by the browser
516: String browserFileName = file.getFileName();
517:
518: // we just want the file name part - strip off any drive and path stuff
519: String name = Validator.getFileName(browserFileName);
520: String resourceId = Validator.escapeResourceName(name);
521:
522: // make a set of properties to add for the new resource
523: ResourcePropertiesEdit props = ContentHostingService
524: .newResourceProperties();
525: props.addProperty(ResourceProperties.PROP_DISPLAY_NAME,
526: name);
527: props.addProperty(ResourceProperties.PROP_DESCRIPTION,
528: browserFileName);
529:
530: // make an attachment resource for this URL
531: try {
532: ContentResource attachment = ContentHostingService
533: .addAttachmentResource(resourceId, contentType,
534: in, props);
535:
536: // add a dereferencer for this to the attachments
537: attachments.add(EntityManager.newReference(attachment
538: .getReference()));
539: } catch (Exception any) {
540: M_log
541: .warn("AttachmentAction"
542: + ".doAdd: exception adding attachment resource (fileName: "
543: + name + "): " + any.toString());
544: }
545:
546: } // if (file!= null)
547:
548: // if there is at least one attachment
549: if (attachments.size() > 0) {
550: state.setAttribute(STATE_HAS_ATTACHMENT_BEFORE,
551: Boolean.TRUE);
552: }
553:
554: // end up in main mode
555: state.setAttribute(STATE_MODE, MODE_MAIN);
556:
557: } // doAdd
558:
559: /**
560: * Handle the eventSubmit_doRemove command to remove the selected attachment(s).
561: */
562: static public void doRemove(RunData data) {
563: SessionState state = ((JetspeedRunData) data)
564: .getPortletSessionState(((JetspeedRunData) data)
565: .getJs_peid());
566:
567: // modify the attachments vector
568: Vector attachments = (Vector) state
569: .getAttribute(STATE_ATTACHMENTS);
570:
571: // read the form to figure out which attachment(s) to remove.
572: String[] selected = data.getParameters().getStrings("select");
573:
574: // if nothing selected, and there's just one attachment, remove it
575: if (selected == null) {
576: if (attachments.size() == 1) {
577: attachments.clear();
578: } else {
579: // leave a message
580: state.setAttribute(
581: VelocityPortletPaneledAction.STATE_MESSAGE, rb
582: .getString("alert"));
583: }
584: }
585:
586: else {
587: // run through these 1 based indexes backwards, so we can remove each without invalidating the rest
588: // ASSUME: they are in ascending order
589: for (int i = selected.length - 1; i >= 0; i--) {
590: try {
591: int index = Integer.parseInt(selected[i]) - 1;
592: attachments.removeElementAt(index);
593: } catch (Exception e) {
594: M_log.warn("AttachmentAction"
595: + ".doRemove(): processing selected [" + i
596: + "] : " + e.toString());
597: }
598: }
599: }
600:
601: // end up in main mode
602: state.setAttribute(STATE_MODE, MODE_MAIN);
603:
604: } // doRemove
605:
606: /**
607: * Handle the eventSubmit_doRemove_all command to remove the selected attachment(s).
608: */
609: static public void doRemove_all(RunData data) {
610: SessionState state = ((JetspeedRunData) data)
611: .getPortletSessionState(((JetspeedRunData) data)
612: .getJs_peid());
613:
614: // modify the attachments vector
615: Vector attachments = (Vector) state
616: .getAttribute(STATE_ATTACHMENTS);
617: attachments.clear();
618:
619: // end up in main mode
620: state.setAttribute(STATE_MODE, MODE_MAIN);
621:
622: } // doRemove_all
623:
624: /**
625: * Handle the eventSubmit_doProperties command to edit the selected attachment's properties. Note: not yet used.
626: */
627: static public void doProperties(RunData data) {
628: SessionState state = ((JetspeedRunData) data)
629: .getPortletSessionState(((JetspeedRunData) data)
630: .getJs_peid());
631:
632: // modify the attachments vector
633: Vector attachments = (Vector) state
634: .getAttribute(STATE_ATTACHMENTS);
635:
636: // read the form to figure out which %%% attachment from the vector to edit.
637: Reference attachment = null;
638: state.setAttribute(STATE_ATTACHMENT, attachment);
639:
640: // end up in properties mode
641: state.setAttribute(STATE_MODE, MODE_PROPERTIES);
642:
643: } // doProperties
644:
645: /**
646: * Handle the eventSubmit_doCancel_browse command to abort the browse.
647: */
648: static public void doCancel_browse(RunData data) {
649: SessionState state = ((JetspeedRunData) data)
650: .getPortletSessionState(((JetspeedRunData) data)
651: .getJs_peid());
652:
653: // clean up any browse state
654: state.removeAttribute(STATE_BROWSE_COLLECTION_ID);
655: state.removeAttribute(STATE_HOME_COLLECTION_ID);
656:
657: // end up in main mode
658: state.setAttribute(STATE_MODE, MODE_MAIN);
659:
660: } // doCancel_browse
661:
662: /**
663: * Handle the eventSubmit_doCancel_add command to abort an add.
664: */
665: static public void doCancel_add(RunData data) {
666: SessionState state = ((JetspeedRunData) data)
667: .getPortletSessionState(((JetspeedRunData) data)
668: .getJs_peid());
669:
670: // end up in main mode
671: state.setAttribute(STATE_MODE, MODE_MAIN);
672:
673: } // doCancel_add
674:
675: /**
676: * Handle the eventSubmit_doBrowse_option command to process inputs from the browse form: go up, go down, or be done.
677: */
678: static public void doBrowse_option(RunData data) {
679: SessionState state = ((JetspeedRunData) data)
680: .getPortletSessionState(((JetspeedRunData) data)
681: .getJs_peid());
682:
683: // which option was choosen?
684: String option = data.getParameters().getString("option");
685: if (option.equals("cancel")) {
686: doCancel_add(data);
687: } else {
688: // read the form / state to figure out which attachment(s) to add.
689: String[] ids = data.getParameters().getStrings(
690: "selectedMembers");
691: Vector idVector = new Vector();
692: if ((ids != null) && (ids.length > 0)) {
693: for (int index = 0; index < ids.length; index++) {
694: idVector.add(ids[index]);
695: }
696: }
697: updateAttachments(state, idVector);
698: // if there is at least one resource chosed to be added
699: if (idVector.size() > 0) {
700: state.setAttribute(STATE_HAS_ATTACHMENT_BEFORE,
701: Boolean.TRUE);
702: }
703:
704: if (option.equals("up")) {
705: // get the current collection
706: String id = (String) state
707: .getAttribute(STATE_BROWSE_COLLECTION_ID);
708:
709: // if we are at the home collection, we go no up-er
710: if (id.equals(state
711: .getAttribute(STATE_HOME_COLLECTION_ID)))
712: return;
713:
714: // get the containing collection
715: String containingId = ContentHostingService
716: .getContainingCollectionId(id);
717:
718: // make sure the user can read that
719: if (ContentHostingService
720: .allowGetCollection(containingId)) {
721: state.setAttribute(STATE_BROWSE_COLLECTION_ID,
722: containingId);
723: } else {
724: state.setAttribute(
725: VelocityPortletPaneledAction.STATE_MESSAGE,
726: rb.getString("alert2"));
727: }
728:
729: // end up in browse mode
730: state.setAttribute(STATE_MODE, MODE_BROWSE);
731: }
732:
733: else if (option.equals("down")) {
734: // get the collection id to move to
735: String id = data.getParameters().getString("itemId");
736:
737: // make sure the user can read that
738: if (ContentHostingService.allowGetCollection(id)) {
739: state.setAttribute(STATE_BROWSE_COLLECTION_ID, id);
740: } else {
741: state.setAttribute(
742: VelocityPortletPaneledAction.STATE_MESSAGE,
743: rb.getString("alert2"));
744: }
745:
746: // end up in browse mode
747: state.setAttribute(STATE_MODE, MODE_BROWSE);
748: } else
749: // done
750: {
751: // clean up any browse state
752: state.removeAttribute(STATE_BROWSE_COLLECTION_ID);
753: state.removeAttribute(STATE_HOME_COLLECTION_ID);
754:
755: // end up in main mode
756: state.setAttribute(STATE_MODE, MODE_MAIN);
757: }
758: }
759:
760: } // doBrowse_option
761:
762: /**
763: * Update the attachments list based on which ids were selected at this browse level.
764: */
765: static private void updateAttachments(SessionState state, Vector ids) {
766: String id = (String) state
767: .getAttribute(STATE_BROWSE_COLLECTION_ID);
768: List attachments = (List) state.getAttribute(STATE_ATTACHMENTS);
769:
770: List members = null;
771: try {
772: // get the set of member ids
773: ContentCollection collection = ContentHostingService
774: .getCollection(id);
775: members = collection.getMembers();
776:
777: // for each member
778: for (int i = 0; i < members.size(); i++) {
779: String memberId = (String) members.get(i);
780: String ref = ContentHostingService
781: .getReference(memberId);
782:
783: // if the member id is in the list of ids selected
784: if (ids.contains(memberId)) {
785: // make sure it is in the attachments
786: if (!attachments.contains(ref)) {
787: attachments
788: .add(EntityManager.newReference(ref));
789: }
790: } else {
791: // make sure its NOT in the attachments
792: attachments.remove(ref);
793: }
794: }
795: } catch (Exception e) {
796: }
797:
798: } // updateAttachments
799:
800: /**
801: * Handle the eventSubmit_doCancel_properties command to abort the properties edit. Note: not yet used.
802: */
803: static public void doCancel_properties(RunData data) {
804: SessionState state = ((JetspeedRunData) data)
805: .getPortletSessionState(((JetspeedRunData) data)
806: .getJs_peid());
807:
808: // clean up any properties state %%%
809: state.removeAttribute(STATE_ATTACHMENT);
810:
811: // end up in main mode
812: state.setAttribute(STATE_MODE, MODE_MAIN);
813:
814: } // doCancel_properties
815:
816: /**
817: * Handle the eventSubmit_doUpdate_properties command to keep the edited properties. Note: not yet used.
818: */
819: static public void doUpdate_properties(RunData data) {
820: SessionState state = ((JetspeedRunData) data)
821: .getPortletSessionState(((JetspeedRunData) data)
822: .getJs_peid());
823:
824: // modify the attachment Reference
825: Reference attachment = (Reference) state
826: .getAttribute(STATE_ATTACHMENT);
827:
828: // read the form / state to get the %%% changes and make them
829:
830: // clean up any properties state %%%
831: state.removeAttribute(STATE_ATTACHMENT);
832:
833: // end up in main mode
834: state.setAttribute(STATE_MODE, MODE_MAIN);
835:
836: } // doUpdate_properties
837:
838: /**
839: * Dispatch function for upload attachment page
840: */
841: static public void doDispatch_attachment_upload(RunData data) {
842: String option = data.getParameters().getString("option");
843: if (option.equalsIgnoreCase("cancel")) {
844: // cancel
845: doCancel_add(data);
846: } else if (option.equalsIgnoreCase("attach")) {
847: // upload
848: doAdd(data);
849: }
850:
851: } // doDispatch_attachment_upload
852:
853: } // AttachmentAction
|