2 * Copyright (C) 2012 Openismus GmbH
4 * This file is part of GWT-Glom.
6 * GWT-Glom is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
11 * GWT-Glom is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with GWT-Glom. If not, see <http://www.gnu.org/licenses/>.
20 package org.glom.web.server.libglom;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Hashtable;
25 import java.util.List;
27 import javax.xml.parsers.DocumentBuilder;
28 import javax.xml.parsers.DocumentBuilderFactory;
29 import javax.xml.parsers.ParserConfigurationException;
31 import org.apache.commons.lang3.StringUtils;
32 import org.glom.web.shared.libglom.Field;
33 import org.glom.web.shared.libglom.NumericFormat;
34 import org.glom.web.shared.libglom.Relationship;
35 import org.glom.web.shared.libglom.Report;
36 import org.glom.web.shared.libglom.Translatable;
37 import org.glom.web.shared.libglom.layout.Formatting;
38 import org.glom.web.shared.libglom.layout.LayoutGroup;
39 import org.glom.web.shared.libglom.layout.LayoutItemField;
40 import org.glom.web.shared.libglom.layout.LayoutItemNotebook;
41 import org.glom.web.shared.libglom.layout.LayoutItemPortal;
42 import org.glom.web.shared.libglom.layout.UsesRelationship;
43 import org.glom.web.shared.libglom.layout.UsesRelationshipImpl;
44 import org.glom.web.shared.libglom.layout.reportparts.LayoutItemGroupBy;
45 import org.jfree.util.Log;
46 import org.w3c.dom.Element;
47 import org.w3c.dom.Node;
48 import org.w3c.dom.NodeList;
49 import org.xml.sax.SAXException;
52 * @author Murray Cumming <murrayc@openismus.com>
55 public class Document {
57 @SuppressWarnings("serial")
58 private class TableInfo extends Translatable {
59 public boolean isDefault;
60 public boolean isHidden;
62 private final Hashtable<String, Field> fieldsMap = new Hashtable<String, Field>();
63 private final Hashtable<String, Relationship> relationshipsMap = new Hashtable<String, Relationship>();
64 private final Hashtable<String, Report> reportsMap = new Hashtable<String, Report>();
66 private List<LayoutGroup> layoutGroupsList = new ArrayList<LayoutGroup>();
67 private List<LayoutGroup> layoutGroupsDetails = new ArrayList<LayoutGroup>();
70 private String fileURI = "";
71 private org.w3c.dom.Document xmlDocument = null;
73 private Translatable databaseTitle = new Translatable();
74 private List<String> translationAvailableLocales = new ArrayList<String>(); // TODO
75 private String connectionServer = "";
76 private String connectionDatabase = "";
77 private int connectionPort = 0;
78 private final Hashtable<String, TableInfo> tablesMap = new Hashtable<String, TableInfo>();
80 private static final String NODE_CONNECTION = "connection";
81 private static final String ATTRIBUTE_CONNECTION_SERVER = "server";
82 private static final String ATTRIBUTE_CONNECTION_DATABASE = "database";
83 private static final String ATTRIBUTE_CONNECTION_PORT = "port";
84 private static final String NODE_TABLE = "table";
85 private static final String ATTRIBUTE_NAME = "name";
86 private static final String ATTRIBUTE_TITLE = "title";
87 private static final String ATTRIBUTE_DEFAULT = "default";
88 private static final String ATTRIBUTE_HIDDEN = "hidden";
89 private static final String NODE_TRANSLATIONS_SET = "trans_set";
90 private static final String NODE_TRANSLATIONS = "trans";
91 private static final String ATTRIBUTE_TRANSLATION_LOCALE = "loc";
92 private static final String ATTRIBUTE_TRANSLATION_TITLE = "val";
93 private static final String NODE_REPORTS = "reports";
94 private static final String NODE_REPORT = "report";
95 private static final String NODE_FIELDS = "fields";
96 private static final String NODE_FIELD = "field";
97 private static final String ATTRIBUTE_PRIMARY_KEY = "primary_key";
98 private static final String ATTRIBUTE_FIELD_TYPE = "type";
99 private static final String NODE_FORMATTING = "formatting";
100 private static final String ATTRIBUTE_TEXT_FORMAT_MULTILINE = "format_text_multiline";
101 private static final String ATTRIBUTE_USE_THOUSANDS_SEPARATOR = "format_thousands_separator";
102 private static final String ATTRIBUTE_DECIMAL_PLACES = "format_decimal_places";
103 private static final String NODE_RELATIONSHIPS = "relationships";
104 private static final String NODE_RELATIONSHIP = "relationship";
105 private static final String ATTRIBUTE_RELATIONSHIP_FROM_FIELD = "key";
106 private static final String ATTRIBUTE_RELATIONSHIP_TO_TABLE = "other_table";
107 private static final String ATTRIBUTE_RELATIONSHIP_TO_FIELD = "other_key";
108 private static final String NODE_DATA_LAYOUTS = "data_layouts";
109 private static final String NODE_DATA_LAYOUT = "data_layout";
110 private static final String NODE_DATA_LAYOUT_GROUPS = "data_layout_groups";
111 private static final String NODE_DATA_LAYOUT_GROUP = "data_layout_group";
112 private static final String NODE_DATA_LAYOUT_NOTEBOOK = "data_layout_notebook";
113 private static final String NODE_DATA_LAYOUT_PORTAL = "data_layout_portal";
114 private static final String NODE_DATA_LAYOUT_PORTAL_NAVIGATIONRELATIONSHIP = "portal_navigation_relationship";
115 private static final String ATTRIBUTE_PORTAL_NAVIGATION_TYPE = "navigation_type";
116 private static final String ATTRIBUTE_PORTAL_NAVIGATION_TYPE_AUTOMATIC = "automatic";
117 private static final String ATTRIBUTE_PORTAL_NAVIGATION_TYPE_SPECIFIC = "specific";
118 private static final String ATTRIBUTE_PORTAL_NAVIGATION_TYPE_NONE = "none";
119 private static final String ATTRIBUTE_RELATIONSHIP_NAME = "relationship";
120 private static final String ATTRIBUTE_RELATED_RELATIONSHIP_NAME = "related_relationship";
121 private static final String NODE_DATA_LAYOUT_ITEM = "data_layout_item";
122 private static final String NODE_DATA_LAYOUT_ITEM_GROUPBY = "data_layout_item_groupby";
123 private static final String NODE_GROUPBY = "groupby";
124 private static final String NODE_SECONDARY_FIELDS = "secondary_fields";
125 private static final String ATTRIBUTE_USE_DEFAULT_FORMATTING = "use_default_formatting";
126 private static final String LAYOUT_NAME_DETAILS = "details";
127 private static final String LAYOUT_NAME_LIST = "list";
129 public void setFileURI(final String fileURI) {
130 this.fileURI = fileURI;
133 public String getFileURI() {
137 // TODO: Make sure these have the correct values.
138 public enum LoadFailureCodes {
139 LOAD_FAILURE_CODE_NONE, LOAD_FAILURE_CODE_NOT_FOUND, LOAD_FAILURE_CODE_FILE_VERSION_TOO_NEW
142 public boolean load(final int failure_code) {
143 final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
144 DocumentBuilder documentBuilder;
146 documentBuilder = dbf.newDocumentBuilder();
147 } catch (final ParserConfigurationException e) {
148 // TODO Auto-generated catch block
154 xmlDocument = documentBuilder.parse(fileURI);
155 } catch (final SAXException e) {
156 // TODO Auto-generated catch block
159 } catch (final IOException e) {
160 // TODO Auto-generated catch block
165 final Element rootNode = xmlDocument.getDocumentElement();
166 if (rootNode.getNodeName() != "glom_document") {
167 Log.error("Unexpected XML root node name found: " + rootNode.getNodeName());
171 databaseTitle.setTitleOriginal(rootNode.getAttribute(ATTRIBUTE_TITLE));
173 // We first load the fields, relationships, etc,
175 final List<Node> listTableNodes = getChildrenByTagName(rootNode, NODE_TABLE);
176 for (final Node node : listTableNodes) {
177 if (!(node instanceof Element))
180 final Element element = (Element) node;
181 final TableInfo info = loadTableNodeBasic(element);
182 tablesMap.put(info.getName(), info);
185 // We then load the layouts for all tables, because they
186 // need the fields and relationships for all tables:
187 for (final Node node : listTableNodes) {
188 if (!(node instanceof Element))
191 final Element element = (Element) node;
192 final String tableName = element.getAttribute(ATTRIBUTE_NAME);
194 // We first load the fields, relationships, etc:
195 final TableInfo info = getTableInfo(tableName);
200 // We then load the layouts afterwards, because they
201 // need the fields and relationships:
202 loadTableLayouts(element, info);
204 tablesMap.put(info.getName(), info);
207 final Element nodeConnection = getElementByName(rootNode, NODE_CONNECTION);
208 if (nodeConnection != null) {
209 connectionServer = nodeConnection.getAttribute(ATTRIBUTE_CONNECTION_SERVER);
210 connectionDatabase = nodeConnection.getAttribute(ATTRIBUTE_CONNECTION_DATABASE);
211 connectionPort = getAttributeAsDecimal(nodeConnection,
212 nodeConnection.getAttribute(ATTRIBUTE_CONNECTION_PORT));
218 private Element getElementByName(final Element parentElement, final String tagName) {
219 final List<Node> listNodes = getChildrenByTagName(parentElement, tagName);
220 if (listNodes == null)
223 if (listNodes.size() == 0)
226 return (Element) listNodes.get(0);
229 private boolean getAttributeAsBoolean(final Element node, final String attributeName) {
230 final String str = node.getAttribute(attributeName);
234 return str.equals("true");
238 * @param elementFormatting
239 * @param aTTRIBUTE_DECIMAL_PLACES2
242 private int getAttributeAsDecimal(final Element node, final String attributeName) {
243 final String str = node.getAttribute(attributeName);
244 if (StringUtils.isEmpty(str))
247 return Integer.valueOf(str);
251 * Load a title and its translations.
254 * The XML Element that may contain a title attribute and a trans_set of translations of the title.
257 private void loadTitle(final Element node, final Translatable title) {
258 title.setName(node.getAttribute(ATTRIBUTE_NAME));
260 title.setTitleOriginal(node.getAttribute(ATTRIBUTE_TITLE));
262 final Element nodeSet = getElementByName(node, NODE_TRANSLATIONS_SET);
263 if (nodeSet == null) {
267 final List<Node> listNodes = getChildrenByTagName(nodeSet, NODE_TRANSLATIONS);
268 if (listNodes == null)
271 for (final Node transNode : listNodes) {
272 if (!(transNode instanceof Element)) {
276 final Element element = (Element) transNode;
278 final String locale = element.getAttribute(ATTRIBUTE_TRANSLATION_LOCALE);
279 final String translatedTitle = element.getAttribute(ATTRIBUTE_TRANSLATION_TITLE);
280 if (!StringUtils.isEmpty(locale) && !StringUtils.isEmpty(translatedTitle)) {
281 title.setTitle(translatedTitle, locale);
290 private TableInfo loadTableNodeBasic(final Element tableNode) {
291 final TableInfo info = new TableInfo();
292 loadTitle(tableNode, info);
293 final String tableName = info.getName();
295 info.isDefault = getAttributeAsBoolean(tableNode, ATTRIBUTE_DEFAULT);
296 info.isHidden = getAttributeAsBoolean(tableNode, ATTRIBUTE_HIDDEN);
298 // These should be loaded before the fields, because the fields use them.
299 final Element relationshipsNode = getElementByName(tableNode, NODE_RELATIONSHIPS);
300 if (relationshipsNode != null) {
301 final List<Node> listNodes = getChildrenByTagName(relationshipsNode, NODE_RELATIONSHIP);
302 for (final Node node : listNodes) {
303 if (!(node instanceof Element)) {
307 final Element element = (Element) node;
308 final Relationship relationship = new Relationship();
309 loadTitle(element, relationship);
310 relationship.setFromTable(tableName);
311 relationship.setFromField(element.getAttribute(ATTRIBUTE_RELATIONSHIP_FROM_FIELD));
312 relationship.setToTable(element.getAttribute(ATTRIBUTE_RELATIONSHIP_TO_TABLE));
313 relationship.setToField(element.getAttribute(ATTRIBUTE_RELATIONSHIP_TO_FIELD));
315 info.relationshipsMap.put(relationship.getName(), relationship);
319 final Element fieldsNode = getElementByName(tableNode, NODE_FIELDS);
320 if (fieldsNode != null) {
321 final List<Node> listNodes = getChildrenByTagName(fieldsNode, NODE_FIELD);
322 for (final Node node : listNodes) {
323 if (!(node instanceof Element)) {
327 final Element element = (Element) node;
328 final Field field = new Field();
329 loadField(element, field);
331 info.fieldsMap.put(field.getName(), field);
342 private void loadTableLayouts(final Element tableNode, final TableInfo info) {
343 final String tableName = info.getName();
345 final Element layoutsNode = getElementByName(tableNode, NODE_DATA_LAYOUTS);
346 if (layoutsNode != null) {
347 final List<Node> listNodes = getChildrenByTagName(layoutsNode, NODE_DATA_LAYOUT);
348 for (final Node node : listNodes) {
349 if (!(node instanceof Element)) {
353 final Element element = (Element) node;
354 final String name = element.getAttribute("name");
355 final List<LayoutGroup> listLayoutGroups = loadLayoutNode(element, tableName);
356 if (name.equals(LAYOUT_NAME_DETAILS)) {
357 info.layoutGroupsDetails = listLayoutGroups;
358 } else if (name.equals(LAYOUT_NAME_LIST)) {
359 info.layoutGroupsList = listLayoutGroups;
361 Log.error("loadTableNode(): unexpected layout name: " + name);
366 final Element reportsNode = getElementByName(tableNode, NODE_REPORTS);
367 if (reportsNode != null) {
368 final List<Node> listNodes = getChildrenByTagName(reportsNode, NODE_REPORT);
369 for (final Node node : listNodes) {
370 if (!(node instanceof Element)) {
374 final Element element = (Element) node;
375 final Report report = new Report();
376 loadReport(element, report, tableName);
378 info.reportsMap.put(report.getName(), report);
387 private List<LayoutGroup> loadLayoutNode(final Element node, final String tableName) {
392 final List<LayoutGroup> result = new ArrayList<LayoutGroup>();
394 final List<Node> listNodes = getChildrenByTagName(node, NODE_DATA_LAYOUT_GROUPS);
395 for (final Node nodeGroups : listNodes) {
396 if (!(nodeGroups instanceof Element)) {
400 final Element elementGroups = (Element) nodeGroups;
402 final NodeList list = elementGroups.getChildNodes();
403 final int num = list.getLength();
404 for (int i = 0; i < num; i++) {
405 final Node nodeLayoutGroup = list.item(i);
406 if (nodeLayoutGroup == null) {
410 if (!(nodeLayoutGroup instanceof Element)) {
414 final Element element = (Element) nodeLayoutGroup;
415 final String tagName = element.getTagName();
416 if (tagName == NODE_DATA_LAYOUT_GROUP) {
417 final LayoutGroup group = new LayoutGroup();
418 loadDataLayoutGroup(element, group, tableName);
420 } else if (tagName == NODE_DATA_LAYOUT_NOTEBOOK) {
421 final LayoutItemNotebook group = new LayoutItemNotebook();
422 loadDataLayoutGroup(element, group, tableName);
424 } else if (tagName == NODE_DATA_LAYOUT_PORTAL) {
425 final LayoutItemPortal portal = new LayoutItemPortal();
426 loadDataLayoutPortal(element, portal, tableName);
440 private void loadUsesRelationship(final Element element, final String tableName, final UsesRelationship item) {
441 if (element == null) {
449 final String relationshipName = element.getAttribute(ATTRIBUTE_RELATIONSHIP_NAME);
450 Relationship relationship = null;
451 if (!StringUtils.isEmpty(relationshipName)) {
452 // std::cout << " debug in : tableName=" << tableName << ", relationshipName=" << relationship_name <<
454 relationship = getRelationship(tableName, relationshipName);
455 item.setRelationship(relationship);
457 if (relationship == null) {
458 Log.error("relationship not found: " + relationshipName + ", in table: " + tableName);
462 final String relatedRelationshipName = element.getAttribute(ATTRIBUTE_RELATED_RELATIONSHIP_NAME);
463 if (!StringUtils.isEmpty(relatedRelationshipName) && (relationship != null)) {
464 final Relationship relatedRelationship = getRelationship(relationship.getToTable(), relatedRelationshipName);
465 if (relatedRelationship == null) {
466 Log.error("related relationship not found in table=" + relationship.getToTable() + ", name="
467 + relatedRelationshipName);
469 item.setRelatedRelationship(relatedRelationship);
475 * getElementsByTagName() is recursive, but we do not want that.
481 private List<Node> getChildrenByTagName(final Element parentNode, final String tagName) {
482 final List<Node> result = new ArrayList<Node>();
484 final NodeList list = parentNode.getElementsByTagName(tagName);
485 final int num = list.getLength();
486 for (int i = 0; i < num; i++) {
487 final Node node = list.item(i);
492 final Node itemParentNode = node.getParentNode();
493 if (itemParentNode.equals(parentNode)) {
505 private void loadDataLayoutGroup(final Element nodeGroup, final LayoutGroup group, final String tableName) {
506 loadTitle(nodeGroup, group);
508 final NodeList listNodes = nodeGroup.getChildNodes();
509 final int num = listNodes.getLength();
510 for (int i = 0; i < num; i++) {
511 final Node node = listNodes.item(i);
512 if (!(node instanceof Element))
515 final Element element = (Element) node;
516 final String tagName = element.getTagName();
517 if (tagName == NODE_DATA_LAYOUT_GROUP) {
518 final LayoutGroup childGroup = new LayoutGroup();
519 loadDataLayoutGroup(element, childGroup, tableName);
520 group.addItem(childGroup);
521 } else if (tagName == NODE_DATA_LAYOUT_NOTEBOOK) {
522 final LayoutItemNotebook childGroup = new LayoutItemNotebook();
523 loadDataLayoutGroup(element, childGroup, tableName);
524 group.addItem(childGroup);
525 } else if (tagName == NODE_DATA_LAYOUT_PORTAL) {
526 final LayoutItemPortal childGroup = new LayoutItemPortal();
527 loadDataLayoutPortal(element, childGroup, tableName);
528 group.addItem(childGroup);
529 } else if (element.getTagName() == NODE_DATA_LAYOUT_ITEM) {
530 final LayoutItemField item = new LayoutItemField();
531 loadDataLayoutItemField(element, item, tableName);
533 } else if (element.getTagName() == NODE_DATA_LAYOUT_ITEM_GROUPBY) {
534 final LayoutItemGroupBy item = new LayoutItemGroupBy();
535 loadDataLayoutItemGroupBy(element, item, tableName);
546 private void loadDataLayoutItemGroupBy(final Element element, final LayoutItemGroupBy item, final String tableName) {
547 loadDataLayoutGroup(element, item, tableName);
549 final Element elementGroupBy = getElementByName(element, NODE_GROUPBY);
550 if (elementGroupBy == null) {
554 final LayoutItemField fieldGroupBy = new LayoutItemField();
555 loadDataLayoutItemField(elementGroupBy, fieldGroupBy, tableName);
556 item.setFieldGroupBy(fieldGroupBy);
558 final Element elementSecondaryFields = getElementByName(element, NODE_SECONDARY_FIELDS);
559 if (elementSecondaryFields == null) {
563 final Element elementLayoutGroup = getElementByName(elementSecondaryFields, NODE_DATA_LAYOUT_GROUP);
564 if (elementLayoutGroup != null) {
565 final LayoutGroup secondaryLayoutGroup = new LayoutGroup();
566 loadDataLayoutGroup(elementLayoutGroup, secondaryLayoutGroup, tableName);
567 item.setSecondaryFields(secondaryLayoutGroup);
575 private void loadDataLayoutItemField(final Element element, final LayoutItemField item, final String tableName) {
576 loadTitle(element, item);
577 loadUsesRelationship(element, tableName, item);
579 // Get the actual field:
580 final String fieldName = item.getName();
581 final String inTableName = item.getTableUsed(tableName);
582 final Field field = getField(inTableName, fieldName);
583 item.setFullFieldDetails(field);
585 item.setUseDefaultFormatting(getAttributeAsBoolean(element, ATTRIBUTE_USE_DEFAULT_FORMATTING));
587 final Element elementFormatting = getElementByName(element, NODE_FORMATTING);
588 if (elementFormatting != null) {
589 loadFormatting(elementFormatting, item.getFormatting());
597 private void loadDataLayoutPortal(final Element element, final LayoutItemPortal portal, final String tableName) {
598 loadUsesRelationship(element, tableName, portal);
599 final String relatedTableName = portal.getTableUsed(tableName);
600 loadDataLayoutGroup(element, portal, relatedTableName);
602 final Element elementNavigation = getElementByName(element, NODE_DATA_LAYOUT_PORTAL_NAVIGATIONRELATIONSHIP);
603 if (elementNavigation != null) {
604 final String navigationTypeAsString = elementNavigation.getAttribute(ATTRIBUTE_PORTAL_NAVIGATION_TYPE);
605 if (StringUtils.isEmpty(navigationTypeAsString)
606 || navigationTypeAsString == ATTRIBUTE_PORTAL_NAVIGATION_TYPE_AUTOMATIC) {
607 portal.setNavigationType(LayoutItemPortal.NavigationType.NAVIGATION_AUTOMATIC);
608 } else if (navigationTypeAsString == ATTRIBUTE_PORTAL_NAVIGATION_TYPE_NONE) {
609 portal.setNavigationType(LayoutItemPortal.NavigationType.NAVIGATION_NONE);
610 } else if (navigationTypeAsString == ATTRIBUTE_PORTAL_NAVIGATION_TYPE_SPECIFIC) {
611 // Read the specified relationship name:
612 final UsesRelationship relationshipNavigationSpecific = new UsesRelationshipImpl();
613 loadUsesRelationship(elementNavigation, relatedTableName, relationshipNavigationSpecific);
614 portal.setNavigationRelationshipSpecific(relationshipNavigationSpecific);
624 private void loadField(final Element element, final Field field) {
625 loadTitle(element, field);
627 Field.GlomFieldType fieldType = Field.GlomFieldType.TYPE_INVALID;
628 final String fieldTypeStr = element.getAttribute(ATTRIBUTE_FIELD_TYPE);
629 if (!StringUtils.isEmpty(fieldTypeStr)) {
630 if (fieldTypeStr.equals("Boolean")) {
631 fieldType = Field.GlomFieldType.TYPE_BOOLEAN;
632 } else if (fieldTypeStr.equals("Date")) {
633 fieldType = Field.GlomFieldType.TYPE_DATE;
634 } else if (fieldTypeStr.equals("Image")) {
635 fieldType = Field.GlomFieldType.TYPE_IMAGE;
636 } else if (fieldTypeStr.equals("Number")) {
637 fieldType = Field.GlomFieldType.TYPE_NUMERIC;
638 } else if (fieldTypeStr.equals("Text")) {
639 fieldType = Field.GlomFieldType.TYPE_TEXT;
640 } else if (fieldTypeStr.equals("Time")) {
641 fieldType = Field.GlomFieldType.TYPE_TIME;
645 field.setGlomFieldType(fieldType);
647 field.setPrimaryKey(getAttributeAsBoolean(element, ATTRIBUTE_PRIMARY_KEY));
648 loadTitle(element, field);
650 final Element elementFormatting = getElementByName(element, NODE_FORMATTING);
651 if (elementFormatting != null) {
652 loadFormatting(elementFormatting, field.getFormatting());
657 * @param elementFormatting
660 private void loadFormatting(final Element elementFormatting, final Formatting formatting) {
661 if (elementFormatting == null)
664 if (formatting == null)
667 // formatting.setTextFormatMultiline(getAttributeAsBoolean(elementFormatting, ATTRIBUTE_TEXT_FORMAT_MULTILINE));
669 final NumericFormat numericFormatting = formatting.getNumericFormat();
670 if (numericFormatting != null) {
671 numericFormatting.setUseThousandsSeparator(getAttributeAsBoolean(elementFormatting,
672 ATTRIBUTE_USE_THOUSANDS_SEPARATOR));
673 numericFormatting.setDecimalPlaces(getAttributeAsDecimal(elementFormatting, ATTRIBUTE_DECIMAL_PLACES));
682 private void loadReport(final Element element, final Report report, final String tableName) {
683 report.setName(element.getAttribute(ATTRIBUTE_NAME));
684 loadTitle(element, report);
686 final List<LayoutGroup> listLayoutGroups = loadLayoutNode(element, tableName);
688 // A report can actually only have one LayoutGroup,
689 // though it uses the same XML structure as List and Details layouts,
690 // which (wrongly) suggests that it can have more than one group.
691 LayoutGroup layoutGroup = null;
692 if (!listLayoutGroups.isEmpty()) {
693 layoutGroup = listLayoutGroups.get(0);
696 report.setLayoutGroup(layoutGroup);
699 private TableInfo getTableInfo(final String tableName) {
700 return tablesMap.get(tableName);
703 public enum HostingMode {
704 HOSTING_MODE_POSTGRES_CENTRAL, HOSTING_MODE_POSTGRES_SELF, HOSTING_MODE_SQLITE
707 public String getDatabaseTitle(final String locale) {
708 return databaseTitle.getTitle(locale);
711 public String getDatabaseTitleOriginal() {
712 return databaseTitle.getTitleOriginal();
715 public List<String> getTranslationAvailableLocales() {
716 return translationAvailableLocales;
719 public Document.HostingMode getHostingMode() {
720 return HostingMode.HOSTING_MODE_POSTGRES_CENTRAL; // TODO
723 public String getConnectionServer() {
724 return connectionServer;
727 public long getConnectionPort() {
728 return connectionPort;
731 public String getConnectionDatabase() {
732 return connectionDatabase;
735 public List<String> getTableNames() {
736 // TODO: Return a Set?
737 return new ArrayList<String>(tablesMap.keySet());
740 public boolean getTableIsHidden(final String tableName) {
741 final TableInfo info = getTableInfo(tableName);
746 return info.isHidden;
749 public String getTableTitle(final String tableName, final String locale) {
750 final TableInfo info = getTableInfo(tableName);
755 return info.getTitle(locale);
758 public String getDefaultTable() {
759 for (final TableInfo info : tablesMap.values()) {
760 if (info.isDefault) {
761 return info.getName();
768 public boolean getTableIsKnown(final String tableName) {
769 final TableInfo info = getTableInfo(tableName);
777 public List<Field> getTableFields(final String tableName) {
778 final TableInfo info = getTableInfo(tableName);
782 return new ArrayList<Field>(info.fieldsMap.values());
785 public Field getField(final String tableName, final String strFieldName) {
786 final TableInfo info = getTableInfo(tableName);
790 return info.fieldsMap.get(strFieldName);
793 public List<LayoutGroup> getDataLayoutGroups(final String layoutName, final String parentTableName) {
794 final TableInfo info = getTableInfo(parentTableName);
796 return new ArrayList<LayoutGroup>();
798 if (layoutName == LAYOUT_NAME_DETAILS) {
799 return info.layoutGroupsDetails;
800 } else if (layoutName == LAYOUT_NAME_LIST) {
801 return info.layoutGroupsList;
803 return new ArrayList<LayoutGroup>();
807 public List<String> getReportNames(final String tableName) {
808 final TableInfo info = getTableInfo(tableName);
810 return new ArrayList<String>();
812 return new ArrayList<String>(info.reportsMap.keySet());
815 public Report getReport(final String tableName, final String reportName) {
816 final TableInfo info = getTableInfo(tableName);
820 return info.reportsMap.get(reportName);
828 public Relationship getFieldUsedInRelationshipToOne(final String tableName, final LayoutItemField layoutField) {
830 if (layoutField == null) {
831 Log.error("layoutField was null");
835 Relationship result = null;
837 final String tableUsed = layoutField.getTableUsed(tableName);
838 final TableInfo info = getTableInfo(tableUsed);
840 // This table is special. We would not create a relationship to it using a field:
841 // if(tableUsed == GLOM_STANDARD_TABLE_PREFS_TABLE_NAME)
844 Log.error("table not found: " + tableUsed);
848 // Look at each relationship:
849 final String fieldName = layoutField.getName();
850 for (final Relationship relationship : info.relationshipsMap.values()) {
851 if (relationship != null) {
852 // If the relationship uses the field
853 if (relationship.getFromField() == fieldName) {
854 // if the to_table is not hidden:
855 if (!getTableIsHidden(relationship.getToTable())) {
856 // TODO_Performance: The use of this convenience method means we get the full relationship
857 // information again:
858 if (getRelationshipIsToOne(tableName, relationship.getName())) {
859 result = relationship;
871 * @param relationshipName
874 private boolean getRelationshipIsToOne(final String tableName, final String relationshipName) {
875 final Relationship relationship = getRelationship(tableName, relationshipName);
876 if (relationship != null) {
877 final Field fieldTo = getField(relationship.getToTable(), relationship.getToField());
878 if (fieldTo != null) {
879 return (fieldTo.getPrimaryKey() || fieldTo.getUniqueKey());
888 * @param relationshipName
891 private Relationship getRelationship(final String tableName, final String relationshipName) {
892 final TableInfo info = getTableInfo(tableName);
894 Log.error("table not found: " + tableName);
898 return info.relationshipsMap.get(relationshipName);