001: /*
002: * Copyright 2004 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.frontend.editor;
017:
018: import org.outerj.daisy.repository.schema.*;
019: import org.outerj.daisy.repository.variant.Language;
020: import org.outerj.daisy.repository.AvailableVariant;
021: import org.outerj.daisy.repository.Repository;
022: import org.outerj.daisy.frontend.util.FormHelper;
023: import org.apache.cocoon.forms.formmodel.*;
024: import org.apache.cocoon.forms.datatype.StaticSelectionList;
025: import org.apache.cocoon.forms.event.ActionListener;
026: import org.apache.cocoon.forms.event.ActionEvent;
027: import org.apache.cocoon.forms.FormManager;
028: import org.apache.cocoon.i18n.Bundle;
029: import org.apache.cocoon.i18n.BundleFactory;
030: import org.apache.cocoon.components.flow.FlowHelper;
031: import org.apache.cocoon.components.ContextHelper;
032: import org.apache.avalon.framework.service.ServiceManager;
033: import org.apache.avalon.framework.context.Context;
034: import org.apache.avalon.framework.logger.Logger;
035:
036: import java.util.*;
037:
038: /**
039: * Constructs {@link DocumentEditorForm}s.
040: */
041: public class DocumentEditorFormBuilder {
042: private DocumentType documentType;
043: private String documentId;
044: private long docBranchId;
045: private long docLangId;
046: private long docRefLangId;
047: private ServiceManager serviceManager;
048: private Context context;
049: private Locale locale;
050: private DocumentEditorForm documentEditorForm;
051: private Repository repository;
052: private Logger logger;
053:
054: private DocumentEditorFormBuilder(DocumentType documentType,
055: String documentId, long docBranchId, long docLangId,
056: long docRefLangId, ServiceManager serviceManager,
057: Context context, Locale locale, Repository repository,
058: Logger logger) {
059: this .documentType = documentType;
060: this .serviceManager = serviceManager;
061: this .context = context;
062: this .locale = locale;
063: this .repository = repository;
064: this .logger = logger;
065: this .documentId = documentId;
066: this .docBranchId = docBranchId;
067: this .docLangId = docLangId;
068: this .docRefLangId = docRefLangId;
069: }
070:
071: public static DocumentEditorForm build(DocumentType documentType,
072: String documentId, long docBranchId, long docLangId,
073: long docRefLangId, ServiceManager serviceManager,
074: Context context, Locale locale, Repository repository,
075: Logger logger) throws Exception {
076: return new DocumentEditorFormBuilder(documentType, documentId,
077: docBranchId, docLangId, docRefLangId, serviceManager,
078: context, locale, repository, logger).build();
079: }
080:
081: private DocumentEditorForm build() throws Exception {
082: String branch = repository.getVariantManager().getBranch(
083: docBranchId, false).getName();
084: String language = repository.getVariantManager().getLanguage(
085: docLangId, false).getName();
086: documentEditorForm = new DocumentEditorForm(documentType,
087: documentId, docBranchId, branch, docLangId, language,
088: repository, context);
089:
090: documentEditorForm.setMajorChange(true);
091:
092: Form linksForm = getLinksForm();
093: Form miscForm = getMiscForm();
094: Form additionalPartsAndFieldsForm = getAdditionalPartsAndFieldsForm();
095: Form fieldsForm = getFieldsForm();
096:
097: documentEditorForm.setLinksForm(linksForm);
098: documentEditorForm.setMiscForm(miscForm);
099: documentEditorForm
100: .setAdditionalPartsAndFieldsForm(additionalPartsAndFieldsForm);
101: if (fieldsForm != null)
102: documentEditorForm.setFieldsForm(fieldsForm);
103:
104: PartTypeUse[] partTypeUses = documentType.getPartTypeUses();
105: for (PartTypeUse partTypeUse : partTypeUses) {
106: PartType partType = partTypeUse.getPartType();
107: PartEditor partEditor;
108: if (partTypeUse.isEditable()) {
109: partEditor = PartEditorManager.getPartEditor(partType
110: .getName(), serviceManager, context, logger);
111: if (partEditor == null) {
112: if (partType.isDaisyHtml())
113: partEditor = new HtmlPartEditor.Factory()
114: .getPartEditor(Collections.EMPTY_MAP,
115: serviceManager, context);
116: else
117: partEditor = new UploadPartEditor.Factory()
118: .getPartEditor(Collections.EMPTY_MAP,
119: serviceManager, context);
120: }
121: } else {
122: partEditor = new NonEditablePartEditor.Factory()
123: .getPartEditor(Collections.EMPTY_MAP,
124: serviceManager, context);
125: }
126: Form partEditorForm = partEditor.getForm(partTypeUse,
127: documentEditorForm, repository);
128: partEditorForm.setAttribute("partType", partType);
129: partEditorForm.setAttribute("partEditor", partEditor);
130: documentEditorForm.addPartForm(partTypeUse.getPartType()
131: .getName(), partEditorForm, partEditor
132: .getFormTemplate(), partTypeUse.getPartType()
133: .getLabel(locale), partTypeUse.getPartType()
134: .getDescription(locale), partTypeUse.isRequired());
135: }
136:
137: return documentEditorForm;
138: }
139:
140: private Form getLinksForm() throws Exception {
141: final Form form = FormHelper.createForm(serviceManager,
142: "resources/form/doceditor_links_definition.xml");
143:
144: Action addLink = (Action) form.getChild("addLink");
145: addLink.addActionListener(new ActionListener() {
146: public void actionPerformed(ActionEvent event) {
147: Repeater links = (Repeater) form.getChild("links");
148: links.addRow();
149: }
150: });
151:
152: return form;
153: }
154:
155: private Form getMiscForm() throws Exception {
156: final Form form = FormHelper.createForm(serviceManager,
157: "resources/form/doceditor_misc_definition.xml");
158:
159: Action addCustomField = (Action) form
160: .getChild("addCustomField");
161: addCustomField.addActionListener(new ActionListener() {
162: public void actionPerformed(ActionEvent event) {
163: Repeater customFields = (Repeater) form
164: .getChild("customFields");
165: customFields.addRow();
166: }
167: });
168:
169: Field referenceLanguage = (Field) form
170: .getChild("referenceLanguageId");
171: StaticSelectionList list = new StaticSelectionList(
172: referenceLanguage.getDatatype());
173: list
174: .addItem(
175: -1,
176: getEditorI18nMessage("editdoc.reference-language-none"));
177:
178: Set<Language> candidateReferenceLanguages = new HashSet<Language>();
179:
180: // the document about to be created is a candidate
181: candidateReferenceLanguages.add(repository.getVariantManager()
182: .getLanguage(docLangId, false));
183: // the current reference language is also a candidate
184: if (docRefLangId != -1) {
185: candidateReferenceLanguages.add(repository
186: .getVariantManager().getLanguage(docRefLangId,
187: false));
188: }
189: if (documentId != null) {
190: for (AvailableVariant variant : repository
191: .getAvailableVariants(documentId).getArray()) {
192: candidateReferenceLanguages.add(variant.getLanguage());
193: }
194: }
195:
196: // create a list of possible referenceLanguages sorted by name
197: Language[] languages = repository.getVariantManager()
198: .getAllLanguages(false).getArray();
199: Arrays.sort(languages, new Comparator() {
200: public int compare(Object language0, Object language1) {
201: return ((Language) language0).getName().compareTo(
202: ((Language) language1).getName());
203: }
204: });
205: for (Language language : languages) {
206: if (candidateReferenceLanguages.contains(language)) {
207: list.addItem(language.getId(), language.getName());
208: }
209: }
210:
211: referenceLanguage.setSelectionList(list);
212:
213: return form;
214: }
215:
216: private Form getAdditionalPartsAndFieldsForm() throws Exception {
217: final Form form = FormHelper
218: .createForm(serviceManager,
219: "resources/form/doceditor_additionalPartsAndFields_definition.xml");
220: form.setAttribute("documentEditorForm", documentEditorForm);
221: return form;
222: }
223:
224: private Form getFieldsForm() throws Exception {
225: if (documentType.getFieldTypeUses().length == 0)
226: return null;
227:
228: Form form = createFieldEditorForm(documentType);
229: form.addValidator(new CheckFieldsFormValidator(
230: documentEditorForm));
231: return form;
232: }
233:
234: /**
235: * Dynamically creates a form definition for the given document type.
236: */
237: private Form createFieldEditorForm(DocumentType documentType)
238: throws Exception {
239: FieldTypeUse[] fieldTypeUses = documentType.getFieldTypeUses();
240: FieldEditor[] fieldEditors = new FieldEditor[fieldTypeUses.length];
241: for (int i = 0; i < fieldTypeUses.length; i++) {
242: fieldEditors[i] = FieldEditorManager.getFieldEditor(
243: fieldTypeUses[i], serviceManager, context, logger);
244: }
245:
246: Map objectModel = ContextHelper.getObjectModel(context);
247: Object oldViewData = FlowHelper.getContextObject(objectModel);
248:
249: FormManager formManager = null;
250: try {
251: Map<String, Object> viewData = new HashMap<String, Object>();
252: viewData.put("fieldsFormCacheKey",
253: "daisy-fieldform-documenttype-"
254: + documentType.getId() + "-"
255: + documentType.getUpdateCount());
256: viewData.put("fieldsFormValidity", FieldsFormSourceValidity
257: .getValidity(documentType, fieldEditors, context));
258: viewData.put("documentType", documentType);
259: viewData.put("fieldEditors", fieldEditors);
260: viewData.put("locale", locale);
261:
262: formManager = (FormManager) serviceManager
263: .lookup(FormManager.ROLE);
264: FlowHelper.setContextObject(objectModel, viewData);
265: Form form = formManager
266: .createForm("cocoon:/internal/documentEditor/fieldEditorFormDefinition");
267:
268: // set field editors in attribute on widget and let FieldEditors initialize the widget instance
269: Iterator widgetIt = form.getChildren();
270: while (widgetIt.hasNext()) {
271: Widget widget = (Widget) widgetIt.next();
272: if (widget.getId().startsWith("field_")) {
273: long fieldTypeId = Long.parseLong(widget.getId()
274: .substring(6)); // 6 == length("field_")
275: for (FieldEditor fieldEditor : fieldEditors) {
276: if (fieldEditor.getFieldTypeUse()
277: .getFieldType().getId() == fieldTypeId) {
278: widget.setAttribute("fieldEditor",
279: fieldEditor);
280: fieldEditor.init(widget,
281: new FieldEditorContextImpl());
282: break;
283: }
284: }
285: }
286: }
287:
288: // Custom view data will be added to the normal view data of the form template (see DocumentEditorForm.getActiveFormTemplateViewData)
289: // This is because the form template pipeline also needs to validity object, the fieldEditors array, etc.
290: form.setAttribute("customViewData", viewData);
291:
292: return form;
293: } finally {
294: if (formManager != null)
295: serviceManager.release(formManager);
296:
297: FlowHelper.setContextObject(objectModel, oldViewData);
298: }
299: }
300:
301: private String getEditorI18nMessage(String key) throws Exception {
302: Bundle bundle = null;
303: BundleFactory bundleFactory = (BundleFactory) serviceManager
304: .lookup(BundleFactory.ROLE);
305: try {
306: bundle = bundleFactory.select("resources/i18n", "messages",
307: locale);
308: return bundle.getString(key);
309: } finally {
310: if (bundle != null)
311: bundleFactory.release(bundle);
312: serviceManager.release(bundleFactory);
313: }
314: }
315:
316: class FieldEditorContextImpl implements FieldEditorContext {
317: public Repository getRepository() {
318: return repository;
319: }
320:
321: public long getDocumentBranchId() {
322: return docBranchId;
323: }
324:
325: public long getDocumentLanguageId() {
326: return docLangId;
327: }
328:
329: public Locale getLocale() {
330: return locale;
331: }
332: }
333: }
|