+ The FAQ packages provide functionality for maintaining
+ collections of questions and answers.
+
+
+
+
+
+
diff --git a/ccm-faq/etc/enterprise.init.in b/ccm-faq/etc/enterprise.init.in
new file mode 100644
index 000000000..6077dc177
--- /dev/null
+++ b/ccm-faq/etc/enterprise.init.in
@@ -0,0 +1 @@
+init com.arsdigita.faq.Initializer { }
diff --git a/ccm-faq/pdl/com/arsdigita/faq/Faq.pdl b/ccm-faq/pdl/com/arsdigita/faq/Faq.pdl
new file mode 100644
index 000000000..25e8fee54
--- /dev/null
+++ b/ccm-faq/pdl/com/arsdigita/faq/Faq.pdl
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation; either version 2.1 of
+// the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// $Id: //apps/faq/dev/pdl/com/arsdigita/faq/Faq.pdl#3 $
+// $DateTime: 2004/08/17 23:26:27 $
+model com.arsdigita.faq;
+
+import com.arsdigita.kernel.ACSObject;
+
+import com.arsdigita.web.Application;
+
+object type Faq extends Application {
+
+ component QAPair[0..n] questions =
+ join faqs.faq_id to faq_questions.faq_id;
+
+ reference key (faqs.faq_id);
+
+}
+
+
+object type QAPair extends ACSObject {
+
+ String question = faq_questions.question VARCHAR(1000);
+ String answer = faq_questions.answer VARCHAR(1000);
+ String answerFormat = faq_questions.answer_format VARCHAR(100);
+ Integer sortKey = faq_questions.sort_key INTEGER;
+
+ Faq[1..1] faq = join faq_questions.faq_id to faqs.faq_id;
+
+ reference key (faq_questions.question_id);
+
+}
+
+
+query nextSortKey {
+ Integer nextSortKey;
+ do {
+ select CASE WHEN max(sort_key) is null THEN 0
+ ELSE max(sort_key) END + 1 as next_sort_key
+ from faq_questions
+ where faq_id = :faqID
+ } map {
+ nextSortKey = faq_questions.next_sort_key;
+ }
+}
diff --git a/ccm-faq/pdl/com/arsdigita/faq/FaqQuestionsPortlet.pdl b/ccm-faq/pdl/com/arsdigita/faq/FaqQuestionsPortlet.pdl
new file mode 100644
index 000000000..89c1b02cf
--- /dev/null
+++ b/ccm-faq/pdl/com/arsdigita/faq/FaqQuestionsPortlet.pdl
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation; either version 2.1 of
+// the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// $Id: //apps/faq/dev/pdl/com/arsdigita/faq/FaqQuestionsPortlet.pdl#3 $
+// $DateTime: 2004/08/17 23:26:27 $
+model com.arsdigita.faq;
+
+import com.arsdigita.portal.Portlet;
+
+object type FaqQuestionsPortlet extends Portlet {
+ // Empty
+}
diff --git a/ccm-faq/sql/ccm-faq/default/index-faq_questions_faq_id_idx.sql b/ccm-faq/sql/ccm-faq/default/index-faq_questions_faq_id_idx.sql
new file mode 100644
index 000000000..4cf7af6a0
--- /dev/null
+++ b/ccm-faq/sql/ccm-faq/default/index-faq_questions_faq_id_idx.sql
@@ -0,0 +1,21 @@
+--
+-- Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+--
+-- This library is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU Lesser General Public License
+-- as published by the Free Software Foundation; either version 2.1 of
+-- the License, or (at your option) any later version.
+--
+-- This library is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public
+-- License along with this library; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+--
+-- $Id: //apps/faq/dev/sql/default/index-faq_questions_faq_id_idx.sql#2 $
+-- $DateTime: 2004/08/17 23:26:27 $
+
+create index faq_questions_faq_id_idx on faq_questions(faq_id);
diff --git a/ccm-faq/sql/ccm-faq/oracle-se-create.sql b/ccm-faq/sql/ccm-faq/oracle-se-create.sql
new file mode 100644
index 000000000..77108a61d
--- /dev/null
+++ b/ccm-faq/sql/ccm-faq/oracle-se-create.sql
@@ -0,0 +1,26 @@
+--
+-- Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+--
+-- This library is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU Lesser General Public License
+-- as published by the Free Software Foundation; either version 2.1 of
+-- the License, or (at your option) any later version.
+--
+-- This library is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public
+-- License along with this library; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+--
+-- $Id: //apps/faq/dev/sql/oracle-se-create.sql#4 $
+-- $DateTime: 2004/08/17 23:26:27 $
+
+
+@@ ddl/oracle-se/create.sql
+
+@@ default/index-faq_questions_faq_id_idx.sql
+
+@@ ddl/oracle-se/deferred.sql
diff --git a/ccm-faq/sql/ccm-faq/postgres-create.sql b/ccm-faq/sql/ccm-faq/postgres-create.sql
new file mode 100644
index 000000000..2dbe27900
--- /dev/null
+++ b/ccm-faq/sql/ccm-faq/postgres-create.sql
@@ -0,0 +1,29 @@
+--
+-- Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+--
+-- This library is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU Lesser General Public License
+-- as published by the Free Software Foundation; either version 2.1 of
+-- the License, or (at your option) any later version.
+--
+-- This library is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public
+-- License along with this library; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+--
+-- $Id: //apps/faq/dev/sql/postgres-create.sql#4 $
+-- $DateTime: 2004/08/17 23:26:27 $
+
+begin;
+
+\i ddl/postgres/create.sql
+
+\i default/index-faq_questions_faq_id_idx.sql
+
+\i ddl/postgres/deferred.sql
+
+commit;
diff --git a/ccm-faq/sql/ccm-faq/upgrade/oracle-se-6.x.y-6.x.z.sql b/ccm-faq/sql/ccm-faq/upgrade/oracle-se-6.x.y-6.x.z.sql
new file mode 100644
index 000000000..4ca19ded0
--- /dev/null
+++ b/ccm-faq/sql/ccm-faq/upgrade/oracle-se-6.x.y-6.x.z.sql
@@ -0,0 +1,23 @@
+--
+-- Copyright (C) pb@zes.uni-bremen.de All Rights Reserved.
+--
+-- This library is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU Lesser General Public License
+-- as published by the Free Software Foundation; either version 2.1 of
+-- the License, or (at your option) any later version.
+--
+-- This library is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public
+-- License along with this library; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+--
+
+PROMPT APLAWS ccm-faq 6.x.y -> 6.x.z Upgrade Script (Oracle)
+
+-- Update scripts go here
+@@ ./oracle-se/6.x.0-6.x.1/example_01.sql
+@@ ./default/6.x.0-6.x.1/example_02.sql
diff --git a/ccm-faq/sql/ccm-faq/upgrade/postgres-6.x.y-6.x.z.sql b/ccm-faq/sql/ccm-faq/upgrade/postgres-6.x.y-6.x.z.sql
new file mode 100644
index 000000000..04d834963
--- /dev/null
+++ b/ccm-faq/sql/ccm-faq/upgrade/postgres-6.x.y-6.x.z.sql
@@ -0,0 +1,30 @@
+--
+-- Copyright (C) pb@zes.uni-bremen.de All Rights Reserved.
+--
+-- This library is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU Lesser General Public License
+-- as published by the Free Software Foundation; either version 2.1 of
+-- the License, or (at your option) any later version.
+--
+-- This library is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- Lesser General Public License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public
+-- License along with this library; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+--
+
+\echo APLAWS ccm-faq 6.x.0 -> 6.x.1 Upgrade Script (PostgreSQL)
+
+begin;
+
+-- Update scripts go here
+\i postgres/6.x.0-6.x.1/example_01.sql
+\i postgres/6.x.0-6.x.1/example_02.sql
+
+commit;
+
+
+
diff --git a/ccm-faq/src/ccm-faq.config b/ccm-faq/src/ccm-faq.config
new file mode 100644
index 000000000..adfdba100
--- /dev/null
+++ b/ccm-faq/src/ccm-faq.config
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/ccm-faq/src/ccm-faq.load b/ccm-faq/src/ccm-faq.load
new file mode 100644
index 000000000..1aaa50aaf
--- /dev/null
+++ b/ccm-faq/src/ccm-faq.load
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ccm-faq/src/ccm-faq.upgrade b/ccm-faq/src/ccm-faq.upgrade
new file mode 100644
index 000000000..9f6bd2053
--- /dev/null
+++ b/ccm-faq/src/ccm-faq.upgrade
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/ccm-faq/src/com/arsdigita/faq/ApplicationAuthenticationListener.java b/ccm-faq/src/com/arsdigita/faq/ApplicationAuthenticationListener.java
new file mode 100644
index 000000000..d43ab32b0
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ApplicationAuthenticationListener.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.event.RequestEvent;
+import com.arsdigita.bebop.event.RequestListener;
+
+import com.arsdigita.dispatcher.AccessDeniedException;
+
+
+import com.arsdigita.web.Application;
+import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.permissions.PermissionDescriptor;
+import com.arsdigita.kernel.permissions.PermissionService;
+import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
+
+
+import com.arsdigita.ui.login.UserAuthenticationListener;
+
+import java.io.IOException;
+import org.apache.log4j.Logger;
+
+/**
+ * A RequestListener that verifies the user
+ * has a given privilege on the current Application.
+ *
+ * The user is redirected to ACCESS_DENIED if their is
+ * insufficient permission.
+ *
+ * XXX Permissions will be incorporated in December. This is
+ * temporary for use in our engineering production server until.
+ * that time.
+ *
+ * @param privilegeName a String that represents the privlege name for the
+ * privilege a user must have to see the page.
+ *
+ */
+public class ApplicationAuthenticationListener
+ extends UserAuthenticationListener implements RequestListener {
+ public static final String versionId =
+ "$Id: //apps/faq/dev/src/com/arsdigita/faq/ApplicationAuthenticationListener.java#3 $" +
+ "$Author: dennis $" +
+ "$DateTime: 2004/08/17 23:26:27 $";
+
+ private static final Logger s_log = Logger.getLogger
+ (ApplicationAuthenticationListener.class);
+
+ private String m_privilegeName;
+
+ public ApplicationAuthenticationListener(String privilegeName) {
+ super();
+ m_privilegeName = privilegeName;
+ }
+
+ public void setRequiredPrivilege(String privilegeName) {
+ m_privilegeName = privilegeName;
+ }
+
+ public String getRequiredPrivilege() {
+ return m_privilegeName;
+ }
+
+ /**
+ * Checks whether the user is logged in. If not, redirects the client
+ * to the login page.
+ **/
+ public void pageRequested(RequestEvent event) {
+ PageState state = event.getPageState();
+
+ PrivilegeDescriptor privDescriptor =
+ PrivilegeDescriptor.get(m_privilegeName);
+
+ PermissionDescriptor permDescriptor = new PermissionDescriptor
+ (privDescriptor,
+ Application.getCurrentApplication(state.getRequest()),
+ Kernel.getContext().getParty());
+
+ if (!PermissionService.checkPermission(permDescriptor)) {
+ denyRequest(state);
+ }
+
+ }
+
+ /**
+ * Action performed if authentication failed. Override this to
+ * perform a perform a specific action after the authentication
+ * check.
+ */
+ public void denyRequest(PageState state) {
+ if (Kernel.getContext().getParty() == null) {
+ Util.redirectToLoginPage(state);
+ return;
+ }
+
+ throw new AccessDeniedException();
+ }
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/Faq.java b/ccm-faq/src/com/arsdigita/faq/Faq.java
new file mode 100644
index 000000000..88648c7dd
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/Faq.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq;
+
+import com.arsdigita.domain.DataObjectNotFoundException;
+import com.arsdigita.kernel.permissions.PermissionService;
+import com.arsdigita.persistence.DataAssociation;
+import com.arsdigita.persistence.DataObject;
+import com.arsdigita.persistence.DataQuery;
+import com.arsdigita.persistence.OID;
+import com.arsdigita.persistence.SessionManager;
+import com.arsdigita.util.TypedText;
+
+import com.arsdigita.web.Application;
+
+import java.math.BigDecimal;
+
+/**
+ * Faq class.
+ *
+ */
+
+public class Faq extends Application {
+
+ public static final String versionId = "$Id: //apps/faq/dev/src/com/arsdigita/faq/Faq.java#5 $ by $Author: dennis $, $DateTime: 2004/08/17 23:26:27 $";
+
+ public static final String BASE_DATA_OBJECT_TYPE =
+ "com.arsdigita.faq.Faq";
+
+ private static final org.apache.log4j.Logger log =
+ org.apache.log4j.Logger.getLogger(Faq.class);
+
+ public Faq(OID oid) throws DataObjectNotFoundException {
+ super(oid);
+ }
+
+ public Faq(BigDecimal key) throws DataObjectNotFoundException {
+ this(new OID(BASE_DATA_OBJECT_TYPE, key));
+ }
+
+ public Faq(DataObject dataObject) {
+ super(dataObject);
+ }
+
+ protected String getBaseDataObjectType() {
+ return BASE_DATA_OBJECT_TYPE;
+ }
+
+
+ /**
+ * Use this instead of the constructor to create new Faq objects
+ */
+ public static Faq create(String urlName, String title,
+ Application parent) {
+ return (Faq) Application.createApplication
+ (BASE_DATA_OBJECT_TYPE, urlName, title, parent);
+ }
+
+ /**
+ *
+ * @param question
+ * @param answer
+ * @return
+ */
+ public QAPair createQuestion(String question, String answer) {
+ return createQuestion(question,
+ new TypedText(answer, TypedText.TEXT_HTML));
+ }
+
+ /**
+ * @deprecated use createQuestion(String, TypedText) instead
+ */
+ public QAPair createQuestion(String question, String answer,
+ String answerFormat) {
+ return createQuestion(question, new TypedText(answer, answerFormat));
+ }
+
+ public QAPair createQuestion(String question, TypedText answer) {
+
+ Integer sortKey = getNextSortKey();
+ QAPair qaPair = new QAPair();
+ qaPair.setFaq(this);
+ qaPair.setQuestion(question);
+ qaPair.setAnswer(answer);
+ qaPair.setSortKey(sortKey);
+ qaPair.save();
+ PermissionService.setContext(qaPair, this);
+
+ return qaPair;
+ }
+
+
+ void removeQAPair(QAPair qaPair) {
+ remove("questions", qaPair);
+ }
+
+ public DataAssociation getQAPairs() {
+ return (DataAssociation) get("questions");
+ }
+
+ /*
+ * XXX synchronization is not really enough. need to lock the
+ * database or risk an error.
+ * (Actually, there's no unique constraint on sort key, so
+ * you won't get an error)
+ */
+ synchronized Integer getNextSortKey() {
+ DataQuery nextVal = SessionManager.getSession().
+ retrieveQuery("com.arsdigita.faq.nextSortKey");
+ nextVal.setParameter("faqID", getID());
+
+ Integer returnVal = null;
+ if (nextVal.next()) {
+ returnVal = (Integer) nextVal.get("nextSortKey");
+ } else {
+ // this should never happen
+ throw new RuntimeException("No rows returned from a query "
+ + "guaranteed to return a row");
+ }
+
+ nextVal.close();
+ return returnVal;
+ }
+
+ /**
+ * Swaps the order of two questions
+ */
+ void swapOrder(QAPair qaPairA, QAPair qaPairB) {
+
+ if (qaPairA.getFaq().equals(this) && qaPairB.getFaq().equals(this)) {
+
+ log.debug("Security passed, swapping: ");
+
+ Integer temp = qaPairA.getSortKey();
+ qaPairA.setSortKey(qaPairB.getSortKey());
+ qaPairB.setSortKey(temp);
+
+ qaPairA.save();
+ qaPairB.save();
+
+ log.debug("Swapped: ");
+ }
+
+ }
+
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/FaqDispatcher.java b/ccm-faq/src/com/arsdigita/faq/FaqDispatcher.java
new file mode 100644
index 000000000..b34fa77bf
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/FaqDispatcher.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq;
+
+import com.arsdigita.faq.ui.FaqPage;
+import com.arsdigita.faq.ui.FaqAdminView;
+import com.arsdigita.faq.ui.FaqUserView;
+
+import com.arsdigita.bebop.page.BebopMapDispatcher;
+import com.arsdigita.bebop.Page;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.log4j.Logger;
+
+/**
+ * Faq dispatcher for both Bebop-backed and other URLs.
+ *
+ * @author Kevin Scaldeferri (kevin@arsdigita.com)
+ * @version $Revision: #4 $ $Date: 2004/08/17 $
+ * @version $Id: FaqDispatcher.java pboy $
+ */
+
+public class FaqDispatcher extends BebopMapDispatcher {
+
+ private static final Logger s_log =
+ Logger.getLogger(FaqDispatcher.class);
+
+ /**
+ *
+ */
+ public FaqDispatcher() {
+ super();
+
+ Map m = new HashMap();
+
+ Page index = buildIndexPage();
+ Page admin = buildAdminIndexPage();
+
+ m.put("", index);
+ m.put("index.jsp", index);
+ m.put("one.jsp", index);
+
+ m.put("admin/", admin);
+ m.put("admin/index.jsp", admin);
+
+ setMap(m);
+ }
+
+ private FaqPage buildIndexPage() {
+ FaqPage p = new FaqPage();
+
+ p.add(new FaqUserView());
+
+ /*CommentsService commentsService =
+ * new CommentsService(req, FaqHelper.getFaqID(req));
+ * p.add(commentsService.buildCommentsComponent(
+ * "comments/one-object"));
+ */
+
+ p.lock();
+ return p;
+ }
+
+
+ private FaqPage buildAdminIndexPage() {
+
+ FaqPage p = new FaqPage("admin");
+
+ FaqAdminView faqAdminTabs = new FaqAdminView();
+ faqAdminTabs.setKey("FaqAdminTabs");
+ p.add(faqAdminTabs);
+
+ p.lock();
+ return p;
+ }
+
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/FaqResources.properties b/ccm-faq/src/com/arsdigita/faq/FaqResources.properties
new file mode 100644
index 000000000..e3e46e3c3
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/FaqResources.properties
@@ -0,0 +1,7 @@
+cw.faq.ui.return_to_all_questions=Return to all questions
+cw.faq.ui.delete_this_question=Delete this question
+cw.faq.ui.question=Question:
+cw.faq.ui.answer=Answer:
+cw.faq.ui.text_type=Text Type:
+cw.faq.ui.user_view=User View
+cw.faq.ui.admin_view=Administration view
diff --git a/ccm-faq/src/com/arsdigita/faq/FaqResources_de.properties b/ccm-faq/src/com/arsdigita/faq/FaqResources_de.properties
new file mode 100644
index 000000000..103a698c9
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/FaqResources_de.properties
@@ -0,0 +1,7 @@
+cw.faq.ui.return_to_all_questions=Zur\u00fcck zur Fragen\u00fcbersicht
+cw.faq.ui.delete_this_question=Diese Frage l\u00f6schen
+cw.faq.ui.question=Frage:
+cw.faq.ui.answer=Antwort:
+cw.faq.ui.text_type=Text Typ:
+cw.faq.ui.user_view=Benutzeransicht
+cw.faq.ui.admin_view=Administrationsansicht
diff --git a/ccm-faq/src/com/arsdigita/faq/FaqResources_en.properties b/ccm-faq/src/com/arsdigita/faq/FaqResources_en.properties
new file mode 100644
index 000000000..e3e46e3c3
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/FaqResources_en.properties
@@ -0,0 +1,7 @@
+cw.faq.ui.return_to_all_questions=Return to all questions
+cw.faq.ui.delete_this_question=Delete this question
+cw.faq.ui.question=Question:
+cw.faq.ui.answer=Answer:
+cw.faq.ui.text_type=Text Type:
+cw.faq.ui.user_view=User View
+cw.faq.ui.admin_view=Administration view
diff --git a/ccm-faq/src/com/arsdigita/faq/Initializer.java b/ccm-faq/src/com/arsdigita/faq/Initializer.java
new file mode 100644
index 000000000..3851032f2
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/Initializer.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq;
+
+import com.arsdigita.db.*;
+import com.arsdigita.dispatcher.ObjectNotFoundException;
+import com.arsdigita.domain.*;
+import com.arsdigita.faq.ui.FaqQuestionsPortlet;
+import com.arsdigita.kernel.ACSObjectInstantiator;
+import com.arsdigita.kernel.NoValidURLException;
+import com.arsdigita.kernel.URLFinder;
+import com.arsdigita.kernel.URLService;
+import com.arsdigita.persistence.*;
+import com.arsdigita.persistence.pdl.*;
+import com.arsdigita.runtime.*;
+
+/**
+ * FAQ Initializer
+ *
+ * @author Jim Parsons <jparsons@redhat.com>
+ * @author Peter Boy <pboy@barkhof.uni-bremen.de>
+ * @version $Revision: #19 $ $Date: 2004/08/17 $
+ **/
+
+public class Initializer extends CompoundInitializer {
+
+
+ public Initializer() {
+ final String url = RuntimeConfig.getConfig().getJDBCURL();
+ final int database = DbHelper.getDatabaseFromURL(url);
+
+ add(new PDLInitializer
+ (new ManifestSource
+ ("ccm-faq.pdl.mf",
+ new NameFilter(DbHelper.getDatabaseSuffix(database), "pdl"))));
+
+ }
+
+ /**
+ *
+ * @param evt
+ */
+ @Override
+ public void init(DomainInitEvent evt) {
+ super.init(evt);
+
+ // Prerequisite to access a faq instance
+ DomainObjectFactory.registerInstantiator(
+ Faq.BASE_DATA_OBJECT_TYPE, new ACSObjectInstantiator() {
+ @Override
+ public DomainObject doNewInstance(DataObject dataObject) {
+ return new Faq(dataObject);
+ }
+ }
+ );
+
+
+ // Registering internal portlets
+
+ // Prerequisite to access FaqQuestionsPortlet
+ DomainObjectFactory.registerInstantiator(
+ FaqQuestionsPortlet.BASE_DATA_OBJECT_TYPE,
+ new ACSObjectInstantiator() {
+ @Override
+ public DomainObject doNewInstance(DataObject dataObject) {
+ return new FaqQuestionsPortlet(dataObject);
+ }
+ }
+ );
+
+ // Enshure URL's are resolved
+ URLFinder faqFinder = new URLFinder() {
+ public String find(OID oid, String context)
+ throws NoValidURLException {
+ return find(oid);
+ }
+ public String find(OID oid) throws NoValidURLException {
+ QAPair pair;
+ try {
+ pair = (QAPair) DomainObjectFactory.newInstance(oid);
+ } catch (DataObjectNotFoundException e) {
+ throw new ObjectNotFoundException("No such FAQ item: " +
+ oid + ". May have been deleted.");
+ }
+
+ String url = pair.getFaq().getPrimaryURL() + "#"
+ + pair.getID();
+ return url;
+
+ }
+ };
+ URLService.registerFinder(QAPair.BASE_DATA_OBJECT_TYPE, faqFinder);
+
+ }
+
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/Loader.java b/ccm-faq/src/com/arsdigita/faq/Loader.java
new file mode 100644
index 000000000..c3fefed48
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/Loader.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq;
+
+// import com.arsdigita.mimetypes.*;
+//import com.arsdigita.domain.DomainObject;
+import com.arsdigita.faq.ui.FaqQuestionsPortlet;
+//import com.arsdigita.kernel.ACSObjectInstantiator;
+import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.KernelExcursion;
+import com.arsdigita.loader.PackageLoader;
+//import com.arsdigita.persistence.DataObject;
+//import com.arsdigita.portal.PortletType;
+//import com.arsdigita.portal.apportlet.AppPortletSetup;
+import com.arsdigita.portal.apportlet.AppPortletType;
+import com.arsdigita.runtime.ScriptContext;
+import com.arsdigita.web.ApplicationType;
+
+import org.apache.log4j.Logger;
+
+/**
+ * FAQ Application Loader
+ *
+ * @author pboy <pboy@barkhof.uni-bremen.de>
+ * @version $Id: Loader.java $
+ */
+public class Loader extends PackageLoader {
+
+
+ /** Logger instance for debugging */
+ private static final Logger s_log = Logger.getLogger(Loader.class);
+
+ /**
+ * Run script invoked by com.arsdigita.packing loader script.
+ *
+ * @param ctx
+ */
+ public void run(final ScriptContext ctx) {
+
+ new KernelExcursion() {
+ public void excurse() {
+ setEffectiveParty(Kernel.getSystemParty());
+
+ loadFAQApplicationType();
+ setupFaqQuestionsPortlet(null);
+
+ setupDefaultFaq();
+
+ }
+ }.run();
+
+ s_log.info("Done");
+ }
+
+ // ////////////////////////////////////////////////////////////////////////
+ //
+ // S e t u p o f a p p l i c a t i o n t y p e s
+ //
+ // ////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates a FAQ application type, the domain class of the
+ * FAQ package, as a legacy-compatible type of application.
+ *
+ * Creates an entry in table application_types and a corresponding entry in
+ * apm_package_types
+ *
+ * TODO: migrate to a new style, legacy free application type.
+ */
+ private void loadFAQApplicationType() {
+
+ ApplicationType type = ApplicationType.createApplicationType(
+ "faq",
+ "Frequently Asked Questions",
+ Faq.BASE_DATA_OBJECT_TYPE);
+ type.setDescription
+ ("FAQ's empower users to share knowledge.");
+ // Current code requires an apps specific dispatcher class. Has to be
+ // modified to be able to create a legacy free app type.
+ type.setDispatcherClass
+ ("com.arsdigita.faq.FaqDispatcher");
+
+ }
+
+
+
+ // ////////////////////////////////////////////////////////////////////////
+ //
+ // S e t u p a F A Q a p p l i c a t i o n
+ //
+ // ////////////////////////////////////////////////////////////////////////
+ private void setupDefaultFaq() {
+
+ // try {
+ // SiteNode sn = SiteNode.getSiteNode("/administration", false);
+ // if (!"administration".equals(sn.getName())) {
+ Faq faq = Faq.create(
+ "faq", "Default FAQ", null);
+ faq.save();
+ // }
+ // } catch (DataObjectNotFoundException e) {
+ // Assert.fail(e.getMessage());
+ // }
+ }
+
+
+ // ////////////////////////////////////////////////////////////////////////
+ //
+ // S e t u p o f i n t e r n a l p o r t l e t s
+ //
+ // ////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Creates a PortletType (persistent object) for the RecentUpdatedDocs
+ * Portlet.
+ *
+ * Instances (Portlets) are created by user interface or programmatically
+ * by configuration.
+ */
+ private void setupFaqQuestionsPortlet(ApplicationType provider) {
+
+ // Create the FAQ questions portlet
+/* Copied from docfrepo as an example
+ AppPortletSetup setup = new AppPortletSetup(s_log);
+
+ setup.setPortletObjectType(RecentUpdatedDocsPortlet.BASE_DATA_OBJECT_TYPE);
+ setup.setTitle("Recently Updated Documents");
+ setup.setDescription(
+ "Displays the most recent documents in the document repository.");
+ setup.setProfile(PortletType.WIDE_PROFILE);
+ // setup.setProviderApplicationType(provider);
+ setup.setProviderApplicationType(Repository.BASE_DATA_OBJECT_TYPE);
+ setup.setInstantiator(new ACSObjectInstantiator() {
+ @Override
+ protected DomainObject doNewInstance(DataObject dataObject) {
+ return new RecentUpdatedDocsPortlet(dataObject);
+ }
+ });
+
+ setup.run();
+*/
+ AppPortletType portletType = AppPortletType.createAppPortletType
+ ("Faq Questions Portlet", AppPortletType.WIDE_PROFILE,
+ FaqQuestionsPortlet.BASE_DATA_OBJECT_TYPE);
+ portletType.setProviderApplicationType(Faq.BASE_DATA_OBJECT_TYPE);
+ portletType.setPortalApplication(true);
+ portletType.save();
+
+ }
+
+
+
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/OldInitializer.java b/ccm-faq/src/com/arsdigita/faq/OldInitializer.java
new file mode 100644
index 000000000..d9a430d6a
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/OldInitializer.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq;
+
+import com.arsdigita.faq.ui.FaqQuestionsPortlet;
+
+import com.arsdigita.domain.DataObjectNotFoundException;
+import com.arsdigita.domain.DomainObject;
+import com.arsdigita.domain.DomainObjectFactory;
+import com.arsdigita.domain.DomainObjectInstantiator;
+import com.arsdigita.initializer.Configuration;
+import com.arsdigita.initializer.InitializationException;
+import com.arsdigita.kernel.*;
+import com.arsdigita.persistence.*;
+import com.arsdigita.web.Application;
+import com.arsdigita.web.ApplicationType;
+import com.arsdigita.portal.apportlet.AppPortletType;
+import com.arsdigita.dispatcher.ObjectNotFoundException;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * OldInitializer
+ *
+ * Initializes the faq package.
+ *
+ *
+ * @author Tracy Adams
+ * @version $Revision: #8 $ $Date: 2004/08/17 $
+ */
+
+public class OldInitializer
+
+ implements com.arsdigita.initializer.Initializer {
+
+ private Configuration m_conf = new Configuration();
+ public static final String versionId = "$Id: //apps/faq/dev/src/com/arsdigita/faq/Initializer.java#8 $ by $Author: dennis $, $DateTime: 2004/08/17 23:26:27 $";
+
+ private static Logger s_log =
+ Logger.getLogger(OldInitializer.class);
+
+ public OldInitializer() throws InitializationException {
+
+ }
+
+ /**
+ * Returns the configuration object used by this initializer.
+ **/
+
+ public Configuration getConfiguration() {
+ return m_conf;
+ }
+
+
+ /**
+ * Called on startup. Note. As you can not find a call
+ * to this method in enterprise.ini, this method
+ * may appear to execute mysteriously.
+ * However, the process that runs through enterprise.ini
+ * automitically calls the startup() method of any
+ * class that implements com.arsdigita.util.initializer.OldInitializer
+ * present in enterprise.ini
+ *
+ **/
+
+
+ public void startup() {
+
+ s_log.info("Faq Initializer starting.");
+
+
+ TransactionContext txn = SessionManager.getSession()
+ .getTransactionContext();
+ txn.beginTxn();
+
+ // Register Faq domain object
+
+ DomainObjectInstantiator instantiator;
+
+ instantiator = new ACSObjectInstantiator() {
+ protected DomainObject doNewInstance(DataObject dataObject) {
+ return new Faq(dataObject);
+ }
+ };
+
+ DomainObjectFactory.registerInstantiator
+ (Faq.BASE_DATA_OBJECT_TYPE, instantiator);
+
+ checkFaqSetup();
+
+
+ // Register the portlets
+ instantiator = new ACSObjectInstantiator() {
+ protected DomainObject doNewInstance(DataObject dataObject) {
+ return new FaqQuestionsPortlet(dataObject);
+ }
+ };
+
+ DomainObjectFactory.registerInstantiator
+ (FaqQuestionsPortlet.BASE_DATA_OBJECT_TYPE, instantiator);
+
+ txn.commitTxn();
+
+ URLFinder faqFinder = new URLFinder() {
+ public String find(OID oid, String context) throws NoValidURLException {
+ return find(oid);
+ }
+ public String find(OID oid) throws NoValidURLException {
+ QAPair pair;
+ try {
+ pair = (QAPair) DomainObjectFactory.newInstance(oid);
+ } catch (DataObjectNotFoundException e) {
+ throw new ObjectNotFoundException("No such FAQ item: " + oid + " .may have been deleted.");
+ }
+
+ String url = pair.getFaq().getPrimaryURL() + "#" + pair.getID();
+ return url;
+
+ }
+ };
+
+ URLService.registerFinder(QAPair.BASE_DATA_OBJECT_TYPE, faqFinder);
+
+ s_log.debug("Faq Initializer done.");
+ }
+
+ private void checkFaqSetup() {
+ /* This checks to see if a package by this name
+ * is present. If it isn't, setupFaq
+ * will do the necessary setup such as add the
+ * package type, package instance, site node
+ * and style sheet.
+ */
+ try {
+ s_log.debug("Faq Initializer - verifying setup.");
+ PackageType FaqType = PackageType.findByKey("faq");
+ } catch (DataObjectNotFoundException e) {
+ setupFaq();
+ }
+ }
+
+
+ private void setupFaq() {
+ s_log.info("Faq Initializer - setting up new package");
+
+ /** Adding the package type to the installation
+ */
+
+ PackageType FaqType = PackageType.create(
+ "faq", "FAQ ", "FAQ s",
+ "http://arsdigita.com/faq");
+ s_log.debug("Just added package type FAQ ");
+
+ /** Adding a style sheet
+ */
+
+ // Stylesheet FaqSheet =
+ // Stylesheet.createStylesheet("/packages/faq/xsl/faq.xsl");
+ // FaqType.addStylesheet(FaqSheet);
+
+
+ /** Mapping the package type to a dispatcher
+ * class
+ */
+
+ FaqType.setDispatcherClass("com.arsdigita.faq.FaqDispatcher");
+
+ /** Saving changes
+ */
+
+ FaqType.save();
+
+ final ApplicationType faqAppType = ApplicationType.createApplicationType
+ (FaqType, "FAQ Application", Faq.BASE_DATA_OBJECT_TYPE);
+ faqAppType.save();
+
+ KernelExcursion ex = new KernelExcursion() {
+ protected void excurse() {
+ setParty(Kernel.getSystemParty());
+ Application faqApp = Application.createApplication
+ (faqAppType, "faq", "FAQ", null);
+ faqApp.save();
+ }
+ };
+ ex.run();
+
+
+ // register the faq portlet
+ AppPortletType portletType = AppPortletType.createAppPortletType
+ ("Faq Questions Portlet", AppPortletType.WIDE_PROFILE,
+ FaqQuestionsPortlet.BASE_DATA_OBJECT_TYPE);
+ portletType.setProviderApplicationType(faqAppType);
+ portletType.setPortalApplication(true);
+ portletType.save();
+
+ }
+
+ /**
+ * Called on shutdown. It's probably not a good idea to depend on this
+ * being called.
+ **/
+
+ public void shutdown() {
+ }
+
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/QAPair.java b/ccm-faq/src/com/arsdigita/faq/QAPair.java
new file mode 100644
index 000000000..7789acc6b
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/QAPair.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq;
+
+import com.arsdigita.domain.DataObjectNotFoundException;
+import com.arsdigita.kernel.ACSObject;
+import com.arsdigita.persistence.DataObject;
+import com.arsdigita.persistence.OID;
+import com.arsdigita.persistence.metadata.ObjectType;
+import com.arsdigita.util.TypedText;
+
+import java.math.BigDecimal;
+
+/**
+ * Represents the question-answer pairs making up a FAQ
+ *
+ */
+
+
+public class QAPair extends ACSObject {
+
+ public static final String versionId = "$Id: //apps/faq/dev/src/com/arsdigita/faq/QAPair.java#4 $ by $Author: dennis $, $DateTime: 2004/08/17 23:26:27 $";
+
+ private static final org.apache.log4j.Logger s_log =
+ org.apache.log4j.Logger.getLogger(QAPair.class);
+
+ public static final String BASE_DATA_OBJECT_TYPE
+ = "com.arsdigita.faq.QAPair";
+
+ private Faq m_faq = null;
+
+ public QAPair() {
+ this(BASE_DATA_OBJECT_TYPE);
+ }
+
+ public QAPair(String typeName) {
+ super(typeName);
+ }
+
+ public QAPair(ObjectType type) {
+ super(type);
+ }
+
+ public QAPair(OID oid) throws DataObjectNotFoundException {
+ super(oid);
+ }
+
+ public QAPair(BigDecimal key) throws DataObjectNotFoundException {
+ this(new OID(BASE_DATA_OBJECT_TYPE, key));
+ }
+
+ public QAPair(DataObject dataObj) {
+ super(dataObj);
+ }
+
+ protected String getBaseDataObjectType() {
+ return BASE_DATA_OBJECT_TYPE;
+ }
+
+
+ public String getQuestion() {
+ return (String) get("question");
+ }
+
+ public void setQuestion(String question) {
+ set("question", question);
+ }
+
+ public Faq getFaq() {
+ if (m_faq == null) {
+ DataObject faqData = (DataObject) get("faq");
+ if (faqData != null) {
+ m_faq = new Faq(faqData);
+ }
+ }
+ return m_faq;
+ }
+
+ public void setFaq(Faq faq) {
+ m_faq = faq;
+ setAssociation("faq", faq);
+ }
+
+ public Integer getSortKey() {
+ return (Integer) get("sortKey");
+ }
+
+ public void setSortKey(Integer sortKey) {
+ set("sortKey", sortKey);
+ }
+
+ public TypedText getAnswer() {
+ return new TypedText((String)get("answer"),
+ (String)get("answerFormat"));
+ }
+
+ public void setAnswer(TypedText answer) {
+ set("answer", answer.getText());
+ set("answerFormat", answer.getType());
+ }
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/Util.java b/ccm-faq/src/com/arsdigita/faq/Util.java
new file mode 100644
index 000000000..076087cb1
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/Util.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.web.Web;
+import com.arsdigita.web.LoginSignal;
+import com.arsdigita.web.URL;
+import com.arsdigita.web.ParameterMap;
+import com.arsdigita.ui.login.LoginHelper;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
+public class Util {
+ public static void redirectToLoginPage(PageState ps) {
+ throw new LoginSignal(ps.getRequest());
+ }
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/AdminQuestionTable.java b/ccm-faq/src/com/arsdigita/faq/ui/AdminQuestionTable.java
new file mode 100644
index 000000000..5634362e9
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/AdminQuestionTable.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+
+import com.arsdigita.bebop.Component;
+import com.arsdigita.bebop.ControlLink;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.Table;
+import com.arsdigita.bebop.table.TableModel;
+import com.arsdigita.bebop.table.TableModelBuilder;
+import com.arsdigita.bebop.table.DefaultTableCellRenderer;
+
+import com.arsdigita.persistence.DataCollection;
+
+import com.arsdigita.util.LockableImpl;
+
+import java.math.BigDecimal;
+
+class AdminQuestionTable extends Table {
+ public static final String versionId = "$Id: //apps/faq/dev/src/com/arsdigita/faq/ui/AdminQuestionTable.java#3 $ by $Author: dennis $, $DateTime: 2004/08/17 23:26:27 $";
+
+ private final static String[] HEADERS = {"#", "Question"};
+
+ public AdminQuestionTable(TableModelBuilder builder) {
+ super(builder, HEADERS);
+ setDefaultCellRenderer(new QuestionCellRenderer());
+ }
+
+
+ static class QuestionModelBuilder extends LockableImpl
+ implements TableModelBuilder {
+
+ public TableModel makeModel(Table t, PageState s) {
+ return new QuestionModel(s);
+ }
+ }
+
+ private static class QuestionModel implements TableModel {
+ private DataCollection m_query = null;
+
+ public QuestionModel(PageState s) {
+ m_query = ((FaqPage)s.getPage()).getFaq(s)
+ .getQAPairs().getDataCollection();
+ }
+
+ public int getColumnCount() { return HEADERS.length; }
+
+ public Object getKeyAt(int columnIndex) {
+ return (BigDecimal)(m_query.get("id"));
+ }
+
+ public Object getElementAt(int columnIndex) {
+ Object ret = null;
+
+ switch (columnIndex) {
+ case 0:
+ ret = m_query.get("sortKey");
+ break;
+
+ case 1:
+ ret = m_query.get("question");
+ break;
+
+ default:
+ ret = "filler";
+ }
+
+ return ret;
+ }
+
+ public boolean nextRow() {
+ return m_query.next();
+ }
+
+ }
+
+ private static class QuestionCellRenderer extends DefaultTableCellRenderer {
+ public Component getComponent(Table table, PageState state,
+ Object value, boolean isSelected,
+ Object key, int row, int column) {
+
+ switch (column) {
+ case 0:
+ return super.getComponent(table, state, value,
+ isSelected, key, row, column);
+ case 1:
+ return new ControlLink(value.toString());
+
+ default:
+ return null;
+ }
+ }
+ }
+
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/AdminQuestionView.java b/ccm-faq/src/com/arsdigita/faq/ui/AdminQuestionView.java
new file mode 100644
index 000000000..2ef9b2bbd
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/AdminQuestionView.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+
+import com.arsdigita.faq.util.GlobalizationUtil;
+
+import com.arsdigita.faq.QAPair;
+import com.arsdigita.bebop.ActionLink;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.ListPanel;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.RequestLocal;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.bebop.SingleSelectionModel;
+import com.arsdigita.bebop.ToggleLink;
+import com.arsdigita.bebop.event.ActionEvent;
+import com.arsdigita.bebop.event.ActionListener;
+import com.arsdigita.bebop.event.PrintEvent;
+import com.arsdigita.bebop.event.PrintListener;
+import com.arsdigita.domain.DataObjectNotFoundException;
+import com.arsdigita.kernel.Kernel;
+import com.arsdigita.kernel.KernelExcursion;
+import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
+import java.math.BigDecimal;
+
+class AdminQuestionView extends SimpleContainer {
+ public static final String versionId =
+ "$Id: //apps/faq/dev/src/com/arsdigita/faq/ui/AdminQuestionView.java#5 $" +
+ "$Author: dennis $" +
+ "$DateTime: 2004/08/17 23:26:27 $";
+
+ private RequestLocal m_question;
+ private SingleSelectionModel m_selection;
+ private ToggleLink m_editLink;
+
+ public AdminQuestionView(final SingleSelectionModel selection) {
+ m_selection = selection;
+
+ ActionLink returnLink = new ActionLink( (String) GlobalizationUtil.globalize("cw.faq.ui.return_to_all_questions").localize());
+ returnLink.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ selection.clearSelection(e.getPageState());
+ }
+ });
+ add(returnLink);
+
+ m_question = new RequestLocal() {
+ protected Object initialValue(PageState s) {
+ try {
+ QAPair qa = new QAPair
+ (new BigDecimal ((String) selection.getSelectedKey(s)));
+ qa.assertPrivilege(PrivilegeDescriptor.READ);
+ return qa;
+ } catch (DataObjectNotFoundException e) {
+ return null;
+ }
+ }
+ };
+
+ Label question = new Label(new PrintListener() {
+ public void prepare(PrintEvent e) {
+ Label l = (Label) e.getTarget();
+ l.setLabel(getQAPair(e.getPageState()).getQuestion());
+ }
+ });
+
+ Label answer = new Label(new PrintListener() {
+ public void prepare(PrintEvent e) {
+ Label l = (Label) e.getTarget();
+ l.setLabel(getQAPair(e.getPageState())
+ .getAnswer().getHTMLText());
+ }
+ });
+
+ add(new QAView(question, answer));
+
+ ListPanel linkList = new ListPanel(ListPanel.UNORDERED);
+
+ m_editLink = new ToggleLink("Edit this question");
+ linkList.add(m_editLink);
+
+ final ActionLink deleteLink = new ActionLink( (String) GlobalizationUtil.globalize("cw.faq.ui.delete_this_question").localize());
+ deleteLink.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ PageState state = e.getPageState();
+ final QAPair pair = getQAPair(state);
+ if ( pair != null ) {
+ KernelExcursion ex = new KernelExcursion() {
+ protected void excurse() {
+ setEffectiveParty(Kernel.getSystemParty());
+ pair.delete();
+ }
+ };
+ ex.run();
+ }
+ selection.clearSelection(state);
+
+ }
+ });
+ deleteLink.setConfirmation("This will permanently delete the question."
+ + " Do you want to do this?");
+ linkList.add(deleteLink);
+ add(linkList);
+ }
+
+ ToggleLink getEditLink() {
+ return m_editLink;
+ }
+
+ private QAPair getQAPair(PageState state) {
+ return (QAPair) m_question.get(state);
+ }
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/AdminQuestionsPane.java b/ccm-faq/src/com/arsdigita/faq/ui/AdminQuestionsPane.java
new file mode 100644
index 000000000..a6134cf23
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/AdminQuestionsPane.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+import com.arsdigita.faq.QAPair;
+import com.arsdigita.bebop.Container;
+import com.arsdigita.bebop.ModalContainer;
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.bebop.SingleSelectionModel;
+import com.arsdigita.bebop.Table;
+import com.arsdigita.bebop.ToggleLink;
+import com.arsdigita.bebop.event.ActionEvent;
+import com.arsdigita.bebop.event.ActionListener;
+import com.arsdigita.domain.DataObjectNotFoundException;
+import com.arsdigita.util.UncheckedWrapperException;
+import com.arsdigita.dispatcher.DispatcherHelper;
+import java.io.IOException;
+import java.math.BigDecimal;
+
+class AdminQuestionsPane extends ModalContainer implements ActionListener {
+ public static final String versionId =
+ "$Id: //apps/faq/dev/src/com/arsdigita/faq/ui/AdminQuestionsPane.java#3 $" +
+ "$Author: dennis $" +
+ "$DateTime: 2004/08/17 23:26:27 $";
+
+ private Container m_questions;
+ private ToggleLink m_newLink;
+ private AdminQuestionView m_questionView;
+ private FaqQuestionEntryForm m_editForm;
+ private SingleSelectionModel m_selection;
+
+ public AdminQuestionsPane() {
+ m_questions = new SimpleContainer();
+ Table questionsTable = new AdminQuestionTable(
+ new AdminQuestionTable.QuestionModelBuilder());
+ m_selection = questionsTable.getRowSelectionModel();
+ m_questions.add(questionsTable);
+
+ m_newLink = new ToggleLink("Add a new question");
+ m_questions.add(m_newLink);
+ add(m_questions);
+ setDefaultComponent(m_questions);
+
+ m_questionView = new AdminQuestionView(m_selection);
+ add(m_questionView);
+
+ m_editForm = new FaqQuestionEntryForm();
+ m_editForm.addCompletionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ PageState s = e.getPageState();
+ if (m_selection.isSelected(s)) {
+ m_questionView.getEditLink().setSelected(s, false);
+ setVisibleComponent(s, m_questionView);
+ } else {
+ m_newLink.setSelected(s, false);
+ setVisibleComponent(s, m_questions);
+ }
+ }
+ });
+
+ add(m_editForm);
+ }
+
+ public void register(Page p) {
+ super.register(p);
+ p.addActionListener(this);
+ ((FaqPage) p).setQuestionSelectionModel(m_selection);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ PageState s = e.getPageState();
+
+ if (m_selection.isSelected(s)) {
+ redirectWhenNotFound(s);
+
+ if (m_questionView.getEditLink().isSelected(s)) {
+ setVisibleComponent(s, m_editForm);
+ } else {
+ setVisibleComponent(s, m_questionView);
+ }
+ } else if (m_newLink.isSelected(s)) {
+ setVisibleComponent(s, m_editForm);
+ } else {
+ setVisibleComponent(s, m_questions);
+ }
+ }
+
+ private void redirectWhenNotFound(PageState state) {
+ BigDecimal id = new BigDecimal
+ ((String) m_selection.getSelectedKey(state));
+
+ try {
+ QAPair pair = new QAPair(id);
+ } catch (DataObjectNotFoundException nfe) {
+ try {
+ DispatcherHelper.sendRedirect
+ (state.getRequest(), state.getResponse(),
+ "/error/object-not-found.jsp");
+ } catch (IOException ioe) {
+ throw new UncheckedWrapperException(ioe);
+ }
+ }
+ }
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/FaqAdminView.java b/ccm-faq/src/com/arsdigita/faq/ui/FaqAdminView.java
new file mode 100644
index 000000000..a505cfe66
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/FaqAdminView.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+import com.arsdigita.bebop.SimpleContainer;
+
+/**
+ * A Bebop component to display the Admin page
+ * for an FAQ.
+ *
+ * @author Tracy Adams
+ * @version $Revision: #3 $ $Date: 2004/08/17 $
+ * @since ACS 4.6.5
+ */
+
+public class FaqAdminView extends SimpleContainer {
+
+ public FaqAdminView() {
+ add(new AdminQuestionsPane());
+ }
+
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/FaqBasePage.java b/ccm-faq/src/com/arsdigita/faq/ui/FaqBasePage.java
new file mode 100644
index 000000000..b06653e6c
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/FaqBasePage.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+
+import com.arsdigita.faq.util.GlobalizationUtil;
+
+import com.arsdigita.bebop.Container;
+import com.arsdigita.bebop.Component;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.bebop.DimensionalNavbar;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.Link;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.parameters.IntegerParameter;
+import com.arsdigita.bebop.event.PrintEvent;
+import com.arsdigita.bebop.event.PrintListener;
+import com.arsdigita.web.Application;
+import com.arsdigita.kernel.Kernel;
+import com.arsdigita.faq.ApplicationAuthenticationListener;
+import com.arsdigita.kernel.permissions.PermissionDescriptor;
+import com.arsdigita.kernel.permissions.PermissionService;
+import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
+import com.arsdigita.xml.Element;
+import com.arsdigita.util.Assert;
+import org.apache.log4j.Logger;
+
+/**
+ *
BasePage class
+ *
+ *
+ * @author Jim Parsons
+ */
+
+public class FaqBasePage extends Page {
+
+ private final Container m_global;
+ private final Container m_header;
+ private final Container m_body;
+ private final Container m_footer;
+
+ private IntegerParameter m_selected = new IntegerParameter("m");
+
+ public static final String FAQ_GLOBAL_ELEMENT = "faq:global";
+ public static final String FAQ_HEADER_ELEMENT = "faq:header";
+ public static final String FAQ_BODY_ELEMENT = "faq:body";
+ public static final String FAQ_FOOTER_ELEMENT = "faq:footer";
+ public static final String FAQ_XML_NS =
+ "http://www.redhat.com/faq/1.0";
+
+ private static final Logger s_log = Logger.getLogger(FaqBasePage.class);
+
+ /*
+ * There are 2 views: user and admin.
+ * m_view determines which context bar and
+ * view link to show.
+ */
+ private String m_view;
+
+ private Link m_viewLink;
+
+ private boolean CHECK_PERMISSION = true;
+
+ public FaqBasePage() {
+ this(null);
+ }
+
+ /**
+ * @param view A String that specifies which application view to
+ * show. Valid values: "user", "admin" and "null". If view is
+ * "null", there will be no right-hand navigation link. Note -
+ * We've decided not to have the right-hand navigation link at
+ * all. Instead, you should create tabs. So, once the
+ * applications are migrated, view will always be null and we can
+ * remove view altogether.
+ */
+ public FaqBasePage(String view) {
+ super(new Label(), new SimpleContainer());
+
+ setClassAttr("faq");
+
+ m_panel = new Panel();
+
+ addGlobalStateParam(m_selected);
+
+ m_global = new SimpleContainer
+ (FAQ_GLOBAL_ELEMENT, FAQ_XML_NS);
+ m_header = new SimpleContainer
+ (FAQ_HEADER_ELEMENT, FAQ_XML_NS);
+ m_body = new SimpleContainer
+ (FAQ_BODY_ELEMENT, FAQ_XML_NS);
+ m_footer = new SimpleContainer
+ (FAQ_FOOTER_ELEMENT, FAQ_XML_NS);
+
+ super.add(m_global);
+ super.add(m_header);
+ super.add(m_body);
+ super.add(m_footer);
+
+
+ m_view = view;
+
+ }
+
+
+ public void lock() {
+ buildPage();
+
+ super.lock();
+ }
+
+ // Only the PortalPage.lock() should invoke this
+ // method, though users of this class may sometimes want to
+ // override this method.
+ protected final void buildPage() {
+ buildTitle();
+ buildContextBar();
+ buildGlobal(getGlobal());
+ buildHeader(getHeader());
+ buildBody(getBody());
+ buildFooter(getFooter());
+ }
+
+
+
+ protected void buildTitle() {
+ class ApplicationAdminLabelPrinter implements PrintListener {
+ public void prepare(PrintEvent e) {
+ Label targetLabel = (Label)e.getTarget();
+ PageState pageState = e.getPageState();
+
+ Application application = Application.getCurrentApplication
+ (pageState.getRequest());
+
+ Assert.exists(application, "application");
+
+ targetLabel.setLabel
+ (application.getTitle() + " Administration");
+ }
+ }
+
+ if (m_view != null && m_view.equals("admin")) {
+ setTitle(new Label(new ApplicationAdminLabelPrinter()));
+ } else {
+ setTitle(new Label(new CurrentApplicationLabelPrinter()));
+ }
+ }
+
+ protected void buildContextBar() {
+ DimensionalNavbar navbar = new DimensionalNavbar();
+
+ navbar.setClassAttr("portalNavbar");
+
+ navbar.add(new Link(new ParentApplicationLinkPrinter()));
+
+ navbar.add(new Link(new CurrentApplicationLinkPrinter()));
+
+ getHeader().add(navbar);
+ }
+
+ protected void buildGlobal(Container global) {
+ Link link = new Link( new Label(GlobalizationUtil.globalize("cw.workspace.sign_out")), "/register/logout");
+
+ link.setClassAttr("signoutLink");
+
+ getGlobal().add(link);
+ }
+
+ protected void buildHeader(Container header) {
+ if (m_view != null) {
+ if (m_view.equals("user")) {
+ m_viewLink = new Link
+ ( new Label(GlobalizationUtil.globalize("cw.faq.ui.admin_view")), "./admin/index.jsp") {
+ public boolean isVisible(PageState ps) {
+ return userIsAdmin(ps);
+ }};
+ } else if (m_view.equals("admin")) {
+ m_viewLink = new Link( new Label(GlobalizationUtil.globalize("cw.faq.ui.user_view")), "../index.jsp");
+ }
+ }
+
+ if (m_viewLink != null) {
+ m_viewLink.setClassAttr("portalControl");
+
+ header.add(m_viewLink);
+ }
+ }
+
+ protected void buildBody(Container body) {
+ // Nothing by default
+ }
+
+ protected void buildFooter(Container footer) {
+ // Nothing by default
+ }
+
+
+
+ private class Panel extends SimpleContainer {
+ public void generateXML(PageState ps, Element p) {
+ Component selected = getSelected(ps);
+ if (selected == null) {
+ super.generateXML(ps, p);
+ } else {
+ SimpleContainer fakeBody =
+ new SimpleContainer(FAQ_BODY_ELEMENT,
+ FAQ_XML_NS);
+ fakeBody.add(selected);
+
+ Element parent = generateParent(p);
+
+ m_header.generateXML(ps, parent);
+ fakeBody.generateXML(ps, parent);
+ m_footer.generateXML(ps, parent);
+ }
+ }
+ }
+
+
+ /**
+ * Makes the given component the only visible component between
+ * the header and footer of this page.
+ */
+ public void goModal(PageState ps, Component c) {
+ Component old = getSelected(ps);
+ if (old != null) {
+ old.setVisible(ps, false);
+ }
+ c.setVisible(ps, true);
+ setSelected(ps, c);
+ }
+
+ private Component getSelected(PageState ps) {
+ Integer stateIndex = (Integer) ps.getValue(m_selected);
+ Component c = null;
+ if (stateIndex != null) {
+ c = getComponent(stateIndex.intValue());
+ }
+
+ return c;
+ }
+
+ private void setSelected(PageState ps, Component c) {
+ if (c == null) {
+ ps.setValue(m_selected, null);
+ } else {
+ ps.setValue(m_selected, new Integer(stateIndex(c)));
+ }
+ }
+
+ /**
+ * Clears the currently selected modal component if it has been set.
+ */
+ public void goUnmodal(PageState ps) {
+ Component old = getSelected(ps);
+ if (old != null) {
+ old.setVisible(ps, false);
+ }
+ setSelected(ps, null);
+ }
+
+ private boolean userIsAdmin(PageState ps) {
+ PermissionDescriptor permDescriptor =
+ new PermissionDescriptor(PrivilegeDescriptor.ADMIN,
+ Application.getCurrentApplication(ps.getRequest()),
+ Kernel.getContext().getParty());
+ return PermissionService.checkPermission(permDescriptor);
+ }
+
+ /**
+ * Adds a component to the body.
+ *
+ * @param pc the component to be added
+ */
+ public void add(Component pc) {
+ Assert.isUnlocked(this);
+ m_body.add(pc);
+ }
+
+ public Container getGlobal() {
+ return m_global;
+ }
+
+ public Container getHeader() {
+ return m_header;
+ }
+
+ public Container getBody() {
+ return m_body;
+ }
+
+ public Container getFooter() {
+ return m_footer;
+ }
+
+ protected class CurrentApplicationLinkPrinter implements PrintListener {
+ public CurrentApplicationLinkPrinter() {
+ // Empty
+ }
+
+ public void prepare(PrintEvent e) {
+ Link link = (Link) e.getTarget();
+ PageState pageState = e.getPageState();
+
+ Application app = Application.getCurrentApplication
+ (pageState.getRequest());
+
+ Assert.exists(app, "Application app");
+
+ link.setChild(new Label(app.getTitle()));
+ link.setTarget(app.getPrimaryURL());
+ }
+ }
+
+ /**
+ *
+ */
+ protected class ParentApplicationLinkPrinter implements PrintListener {
+
+ /**
+ * Empty Default Constructor
+ */
+ public ParentApplicationLinkPrinter() {
+ // Empty
+ }
+
+ public void prepare(PrintEvent e) {
+ Link link = (Link) e.getTarget();
+ PageState pageState = e.getPageState();
+
+ Application app = Application
+ .getCurrentApplication(pageState.getRequest());
+
+ Assert.exists(app, "Application app");
+ Application parent = app.getParentApplication();
+
+ if (parent != null) {
+ link.setChild(new Label(parent.getTitle()));
+ link.setTarget(parent.getPath());
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ protected class CurrentApplicationLabelPrinter implements PrintListener {
+ public CurrentApplicationLabelPrinter() {
+ // Empty
+ }
+
+ public void prepare(PrintEvent e) {
+ Label label = (Label) e.getTarget();
+ PageState pageState = e.getPageState();
+
+ Application app = Application.getCurrentApplication
+ (pageState.getRequest());
+
+ Assert.exists(app, "Application app");
+
+ label.setLabel(app.getTitle());
+ }
+ }
+
+
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/FaqPage.java b/ccm-faq/src/com/arsdigita/faq/ui/FaqPage.java
new file mode 100644
index 000000000..a13c38f70
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/FaqPage.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.SingleSelectionModel;
+import com.arsdigita.util.MessageType;
+import com.arsdigita.util.Assert;
+import com.arsdigita.util.StringUtils;
+
+import com.arsdigita.faq.Faq;
+import com.arsdigita.web.Application;
+import com.arsdigita.faq.ApplicationAuthenticationListener;
+import com.arsdigita.faq.ui.FaqBasePage;
+
+import java.math.BigDecimal;
+
+
+/**
+ * FaqPage is the base Bebop page for the Faq package.
+ *
+ * It includes a common header, a footer, and a main "content"
+ * area. Components are added to the main content area.
+ *
+ * FaqPage also contains static utility methods used by the
+ * throughout the FAQ package.
+ *
+ * @author Tracy Adams
+ * @version $Revision: #4 $ $Date: 2004/08/17 $
+ */
+
+public class FaqPage extends FaqBasePage {
+
+ public static final String versionId = "$Id: //apps/faq/dev/src/com/arsdigita/faq/ui/FaqPage.java#4 $ by $Author: dennis $, $DateTime: 2004/08/17 23:26:27 $";
+
+ private static final org.apache.log4j.Logger log =
+ org.apache.log4j.Logger.getLogger(FaqPage.class);
+
+ public static final String FAQ_XML_NS = "http://www.arsdigita.com/faq/1.0";
+
+ private SingleSelectionModel m_questionSelection;
+
+ public FaqPage() {
+ this("user");
+ }
+
+ public FaqPage(String view) {
+ super(view);
+ if ( view.equals("admin") ) {
+ addRequestListener(new ApplicationAuthenticationListener("admin"));
+ }
+ }
+
+ void setQuestionSelectionModel(SingleSelectionModel selection) {
+ m_questionSelection = selection;
+ }
+
+ BigDecimal getQuestionID(PageState s) {
+ String key = (String) m_questionSelection.getSelectedKey(s);
+ if (StringUtils.emptyString(key)) {
+ return null;
+ } else {
+ return new BigDecimal(key);
+ }
+ }
+
+ /**
+ *
+ * gets the ID of the selected faq. If no faq is selected,
+ * it returns null
+ *
+ * @return the BigDecimal ID of the faq or null if none is selected
+ */
+
+ public BigDecimal getFaqID(PageState state) {
+ Faq faq = getFaq(state);
+ Assert.exists(faq, "faq");
+ return faq.getID();
+ }
+
+ public Faq getFaq(PageState state) {
+ return (Faq)Application.getCurrentApplication(state.getRequest());
+ }
+
+ /** Returns HTML text, converted from the following:
+ * HTML -- returns the input
+ * pre-formatted - returns the input wrapped in
tags
+ * plain - returns the input converted to HTML.
+ */
+
+ public static String generateHTMLText(String text, String formatType) {
+ if (text == null) {
+ return "";
+ }
+ if (formatType.equals(MessageType.TEXT_HTML)) {
+ return text;
+ } else if (formatType.equals(MessageType.TEXT_PREFORMATTED)) {
+ return "
"+text+"
";
+ } else {
+ /*format is plain*/
+ return StringUtils.textToHtml(text);
+ }
+ }
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/FaqQuestionEntryForm.java b/ccm-faq/src/com/arsdigita/faq/ui/FaqQuestionEntryForm.java
new file mode 100644
index 000000000..ae4398318
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/FaqQuestionEntryForm.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+
+import com.arsdigita.faq.util.GlobalizationUtil;
+
+import com.arsdigita.faq.Faq;
+import com.arsdigita.faq.QAPair;
+
+import com.arsdigita.bebop.ColumnPanel;
+import com.arsdigita.bebop.Form;
+import com.arsdigita.bebop.FormData;
+import com.arsdigita.bebop.FormProcessException;
+import com.arsdigita.bebop.FormValidationException;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.RequestLocal;
+import com.arsdigita.bebop.event.FormInitListener;
+import com.arsdigita.bebop.event.FormProcessListener;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.event.FormValidationListener;
+import com.arsdigita.bebop.form.Submit;
+import com.arsdigita.bebop.form.TextArea;
+import com.arsdigita.bebop.form.TextField;
+import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
+import com.arsdigita.bebop.parameters.ParameterModel;
+import com.arsdigita.bebop.parameters.StringLengthValidationListener;
+import com.arsdigita.bebop.parameters.StringParameter;
+
+import com.arsdigita.domain.DataObjectNotFoundException;
+import com.arsdigita.persistence.Filter;
+import com.arsdigita.persistence.DataAssociation;
+import com.arsdigita.persistence.DataAssociationCursor;
+import com.arsdigita.toolbox.ui.TextTypeWidget;
+import com.arsdigita.util.TypedText;
+
+import java.math.BigDecimal;
+
+/**
+ * A reusable component for a faq Question add/edit form
+ */
+public class FaqQuestionEntryForm extends Form
+ implements FormInitListener, FormValidationListener,
+ FormProcessListener {
+ public static final String versionId =
+ "$Id: //apps/faq/dev/src/com/arsdigita/faq/ui/FaqQuestionEntryForm.java#5 $" +
+ "$Author: dennis $" +
+ "$DateTime: 2004/08/17 23:26:27 $";
+
+ private static org.apache.log4j.Logger log
+ = org.apache.log4j.Logger.getLogger(Faq.class);
+
+ private RequestLocal m_faqQuestion;
+
+ FaqQuestionEntryForm() {
+ super("faqQuestionEntry");
+
+ setMethod("POST");
+
+ add(new Label(GlobalizationUtil.globalize("cw.faq.ui.question")));
+ ParameterModel question = new StringParameter("question");
+ question.addParameterListener(new NotEmptyValidationListener());
+ TextField question_tf = new TextField(question);
+ question_tf.setMaxLength(1000);
+ add(question_tf);
+
+ add(new Label(GlobalizationUtil.globalize("cw.faq.ui.answer")));
+
+ ParameterModel answer = new StringParameter("answer");
+ answer.addParameterListener(new NotEmptyValidationListener());
+ answer.addParameterListener(new StringLengthValidationListener(4000));
+ add(new TextArea(answer, 4, 40, TextArea.SOFT));
+
+ add(new Label(GlobalizationUtil.globalize("cw.faq.ui.text_type")));
+ add(new TextTypeWidget(new StringParameter("answerTextType")));
+
+ add(new Submit("Save"), ColumnPanel.CENTER | ColumnPanel.FULL_WIDTH);
+
+ addProcessListener(this);
+ addInitListener(this);
+ addValidationListener(this);
+
+ m_faqQuestion = new RequestLocal() {
+ protected Object initialValue(PageState state) {
+ BigDecimal id =
+ ((FaqPage) state.getPage()).getQuestionID(state);
+
+ if (id == null) {
+ return null;
+ }
+
+ try {
+ return new QAPair(id);
+ } catch (DataObjectNotFoundException nfe) {
+ return null;
+ }
+ }
+ };
+ }
+
+ // Can return null, including when the DataObject is not found.
+ private QAPair getQAPair(PageState state) {
+ QAPair pair = (QAPair) m_faqQuestion.get(state);
+
+ return pair;
+ }
+
+ public void init(FormSectionEvent e) throws FormProcessException {
+ FormData data = e.getFormData();
+ PageState state = e.getPageState();
+
+ BigDecimal id = ((FaqPage) state.getPage()).getQuestionID(state);
+
+ if (id != null) {
+ QAPair pair = getQAPair(state);
+
+ if (pair != null) {
+ data.put("question", pair.getQuestion());
+ data.put("answer", pair.getAnswer().getText());
+ data.put("answerTextType", pair.getAnswer().getType());
+ }
+ }
+ }
+
+ public void validate(FormSectionEvent e) throws FormProcessException {
+ FormData data = e.getFormData();
+ PageState state = e.getPageState();
+
+ QAPair pair = getQAPair(state);
+
+ String name = (String) data.get("question");
+
+ Faq faq = ((FaqPage) state.getPage()).getFaq(state);
+ DataAssociationCursor pairs =
+ ((DataAssociation) faq.getQAPairs()).cursor();
+
+ Filter f = pairs.addFilter("upper(question) = :name");
+ f.set("name", name.toUpperCase());
+
+ BigDecimal id = ((FaqPage) state.getPage()).getQuestionID(state);
+
+ if (id != null) {
+ pairs.addNotEqualsFilter("id", id);
+ }
+
+ if (pairs.next()) {
+ data.addError("question", "This question already exists.");
+ }
+
+ pairs.close();
+ }
+
+ public void process(FormSectionEvent e) throws FormProcessException {
+ FormData data = e.getFormData();
+ PageState state = e.getPageState();
+
+ BigDecimal id = ((FaqPage) state.getPage()).getQuestionID(state);
+
+ Faq faq = ((FaqPage) state.getPage()).getFaq(state);
+ QAPair pair;
+
+ if (id != null) {
+ // We are editing. Get the object we are supposed to change.
+
+ pair = getQAPair(state);
+
+ if (pair == null) {
+ throw new FormValidationException
+ ("The object you are editing cannot be found in the " +
+ "database.");
+ }
+
+ pair.setQuestion((String) data.get("question"));
+ pair.setAnswer
+ (new TypedText((String) data.get("answer"),
+ (String) data.get("answerTextType")));
+ } else {
+ // We are adding. Create a new questionAnswerPair.
+
+ pair = faq.createQuestion
+ ((String) data.get("question"),
+ new TypedText((String) data.get("answer"),
+ (String) data.get("answerTextType")));
+ }
+
+ pair.save();
+
+ fireCompletionEvent(state);
+ }
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/FaqQuestionsPortlet.java b/ccm-faq/src/com/arsdigita/faq/ui/FaqQuestionsPortlet.java
new file mode 100644
index 000000000..0bcbb5bc0
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/FaqQuestionsPortlet.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+import com.arsdigita.bebop.portal.AbstractPortletRenderer;
+import com.arsdigita.persistence.DataObject;
+
+import com.arsdigita.portal.apportlet.AppPortlet;
+
+public class FaqQuestionsPortlet extends AppPortlet {
+ public static final String versionId = "$Id: //apps/faq/dev/src/com/arsdigita/faq/ui/FaqQuestionsPortlet.java#4 $ by $Author: dennis $, $DateTime: 2004/08/17 23:26:27 $";
+
+ public static final String BASE_DATA_OBJECT_TYPE =
+ "com.arsdigita.faq.FaqQuestionsPortlet";
+
+ protected String getBaseDataObjectType() {
+ return BASE_DATA_OBJECT_TYPE;
+ }
+
+ public FaqQuestionsPortlet(DataObject dataObject) {
+ super(dataObject);
+ }
+
+ protected AbstractPortletRenderer doGetPortletRenderer() {
+ return new FaqQuestionsPortletRenderer(this);
+ }
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/FaqQuestionsPortletRenderer.java b/ccm-faq/src/com/arsdigita/faq/ui/FaqQuestionsPortletRenderer.java
new file mode 100644
index 000000000..99bc341f8
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/FaqQuestionsPortletRenderer.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+import com.arsdigita.faq.Faq;
+
+import com.arsdigita.bebop.GridPanel;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.portal.AbstractPortletRenderer;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.xml.Element;
+import com.arsdigita.web.URL;
+import com.arsdigita.persistence.DataAssociationCursor;
+import java.math.BigDecimal;
+
+public class FaqQuestionsPortletRenderer extends AbstractPortletRenderer {
+ public static final String versionId = "$Id: //apps/faq/dev/src/com/arsdigita/faq/ui/FaqQuestionsPortletRenderer.java#4 $ by $Author: dennis $, $DateTime: 2004/08/17 23:26:27 $";
+
+ private FaqQuestionsPortlet m_portlet;
+
+ public FaqQuestionsPortletRenderer(FaqQuestionsPortlet
+ faqQuestionsPortlet) {
+ m_portlet = faqQuestionsPortlet;
+ }
+
+ protected void generateBodyXML(PageState pageState,
+ Element parentElement) {
+ Faq faq = (Faq) m_portlet.getParentApplication();
+
+ DataAssociationCursor questionAnswerPairs =
+ faq.getQAPairs().cursor();
+
+ GridPanel panel = new GridPanel(1);
+
+ String url = URL.getDispatcherPath() + faq.getPrimaryURL();
+
+ while (questionAnswerPairs.next()) {
+ String id = ((BigDecimal) questionAnswerPairs.get("id")).toString();
+ String question = (String) questionAnswerPairs.get("question");
+
+ // TODO - figure out how to do this with a link.
+ // After an hour, I couldn't find a way.
+
+ // the thing which is a problem is setting the fragment
+
+ Label link = new Label("" +
+ question + "", false);
+ panel.add(link);
+ }
+
+ panel.generateXML(pageState, parentElement);
+ }
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/FaqUserView.java b/ccm-faq/src/com/arsdigita/faq/ui/FaqUserView.java
new file mode 100644
index 000000000..a69990b5f
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/FaqUserView.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+import com.arsdigita.bebop.SimpleContainer;
+
+/**
+ * A reusable Bebop component to display the user view of one FAQ.
+ *
+ * @author Tracy Adams
+ * @version $Revision: #3 $ $Date: 2004/08/17 $
+ */
+
+public class FaqUserView extends SimpleContainer {
+
+ public static final String versionId = "$Id: //apps/faq/dev/src/com/arsdigita/faq/ui/FaqUserView.java#3 $ by $Author: dennis $, $DateTime: 2004/08/17 23:26:27 $";
+
+ public FaqUserView() {
+ add(new QAList());
+ }
+
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/QAList.java b/ccm-faq/src/com/arsdigita/faq/ui/QAList.java
new file mode 100644
index 000000000..f663b8c8a
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/QAList.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+import com.arsdigita.faq.Faq;
+import com.arsdigita.faq.QAPair;
+
+import com.arsdigita.bebop.Component;
+import com.arsdigita.bebop.List;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.list.ListCellRenderer;
+import com.arsdigita.bebop.list.ListModel;
+import com.arsdigita.bebop.list.ListModelBuilder;
+
+import com.arsdigita.persistence.DataCollection;
+
+import com.arsdigita.util.LockableImpl;
+
+class QAList extends List {
+
+ public static final String versionId = "$Id: //apps/faq/dev/src/com/arsdigita/faq/ui/QAList.java#3 $ by $Author: dennis $, $DateTime: 2004/08/17 23:26:27 $";
+
+ public QAList() {
+ super();
+ setModelBuilder(new QAListModelBuilder());
+ setCellRenderer(new QACellRenderer());
+ }
+
+ private class QAListModelBuilder extends LockableImpl
+ implements ListModelBuilder {
+
+ public ListModel makeModel(List l, PageState s) {
+ return new QAListModel(s);
+ }
+ }
+
+ private class QAListModel implements ListModel {
+ private DataCollection m_query;
+
+ public QAListModel(PageState s) {
+ Faq faq = ((FaqPage)s.getPage()).getFaq(s);
+ m_query = faq.getQAPairs().getDataCollection();
+ }
+
+ public Object getElement() {
+ return new QAPair(m_query.getDataObject());
+ }
+
+ public String getKey() {
+ return m_query.get("id").toString();
+ }
+
+ public boolean next() {
+ return m_query.next();
+ }
+ }
+
+ private class QACellRenderer implements ListCellRenderer {
+ public Component getComponent(List list, PageState state,
+ Object value, String key,
+ int index, boolean isSelected) {
+ return new QAView((QAPair) value);
+ }
+ }
+
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/ui/QAView.java b/ccm-faq/src/com/arsdigita/faq/ui/QAView.java
new file mode 100644
index 000000000..b747ca0a7
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/ui/QAView.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.ui;
+
+import com.arsdigita.faq.QAPair;
+
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.SimpleContainer;
+
+public class QAView extends SimpleContainer {
+
+ public static final String versionId = "$Id: //apps/faq/dev/src/com/arsdigita/faq/ui/QAView.java#3 $ by $Author: dennis $, $DateTime: 2004/08/17 23:26:27 $";
+
+ public QAView(QAPair qa) {
+ this(qa.getQuestion(), qa.getAnswer().getHTMLText());
+ }
+
+ public QAView(String question, String answer) {
+ this(new Label(question), new Label(answer));
+ }
+
+ public QAView(Label question, Label answer) {
+ super("faq:question-answer-pair", FaqPage.FAQ_XML_NS);
+
+ question.setClassAttr("question");
+ add(question);
+
+ answer.setClassAttr("answer");
+ answer.setOutputEscaping(false);
+ add(answer);
+ }
+}
diff --git a/ccm-faq/src/com/arsdigita/faq/util/GlobalizationUtil.java b/ccm-faq/src/com/arsdigita/faq/util/GlobalizationUtil.java
new file mode 100644
index 000000000..5428cc050
--- /dev/null
+++ b/ccm-faq/src/com/arsdigita/faq/util/GlobalizationUtil.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.faq.util;
+
+import com.arsdigita.globalization.Globalized;
+import com.arsdigita.globalization.GlobalizedMessage;
+
+/**
+ *