DBVIEW
src/org/dbview/databaseExporters/dot/DotMedium.java
00001 /*
00002         DbView - Graph Visualization
00003     Copyright (C) 2012  Denis BEURIVE
00004 
00005     This program is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation, either version 3 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 */
00018 
00019 /**
00020  * @author Denis Beurive
00021  */
00022 
00023 package org.dbview.databaseExporters.dot;
00024 
00025 import java.util.*;
00026 import org.dbview.addons.output.table.utils.dot.*;
00027 import org.dbview.db.structure.Database;
00028 import org.dbview.db.structure.Field;
00029 import org.dbview.db.structure.Table;
00030 import org.dbview.utils.dot.*;
00031 import org.dbview.utils.dot.label.*;
00032 
00033 /**
00034  * This class implements the export to DOT, with an intermediate level of details.
00035  * @see AbstractDatabaseExporter
00036  * @author Denis Beurive
00037  */
00038 public class DotMedium extends AbstractDatabaseExporter
00039 {
00040     /**
00041      * Create the exporter.
00042      * @param in_tables List of tables to export.
00043      * @param in_db Handle to the database.
00044      */
00045     public DotMedium(ArrayList<Table> in_tables, Database in_db)
00046     {
00047         super(in_tables, in_db);
00048     }
00049 
00050     /**
00051      * This method exports the given tables, from the given database.
00052      * @param in_options Options.
00053      *        Options may be:
00054      *        <ul>
00055      *              <li>"layout"</li>
00056      *        </ul>
00057      * @return The method returns a string that represents the DOT representation.
00058      * @throws Exception
00059      */
00060     public String export(Hashtable<String, Object> in_options) throws Exception
00061     {
00062         DiGraph digraph = new DiGraph();
00063         if (null != in_options)
00064         {
00065             if (in_options.containsKey("layout"))
00066             digraph.setRankdir((String)in_options.get("layout"));
00067         }
00068 
00069         // ------------------------------------------------------------------
00070         // Configure the directed graph.
00071         // ------------------------------------------------------------------
00072 
00073         digraph.setNodesep(new Float(0.5));
00074         digraph.setRankset(new Float(0.7));
00075         digraph.setCompound(Boolean.TRUE);
00076 
00077         // ------------------------------------------------------------------
00078         // Add the table.
00079         // ------------------------------------------------------------------
00080 
00081         for (Table table : this._tables)
00082         {
00083             Node table_node = new Node(table.getName());
00084             table_node.setShape("record");
00085             table_node.setStyle("bold");
00086             table_node.setLabel(this.__createMediumTableLabel(table, digraph.getRankdir()));
00087 
00088             SubGraph sub_graph = new SubGraph(table.getName());
00089             sub_graph.setStyle("filled");
00090             sub_graph.setBackgroundColor(Conf.TABLE_BG_COLOR);
00091             sub_graph.setNodeStyle("filled");
00092             sub_graph.setNodeColor(Conf.TABLE_GRID_COLOR);
00093             sub_graph.setLabel(table.getName());
00094             sub_graph.addNode(table_node);
00095 
00096             digraph.addSubGraph(sub_graph);
00097         }
00098 
00099         // ------------------------------------------------------------------
00100         // Add the joins between tables.
00101         // ------------------------------------------------------------------
00102 
00103         Integer looper = 0;
00104         for (Table dependant_table : this._tables)
00105         {
00106             for (Table reference_table : this._db.getReferenceTables(dependant_table))
00107             {
00108                 // WARNING: If we work on a sub list of the total list of tables (zoom level is activated), then some target's tables may not be printed!
00109                 if (! this._tables.contains(reference_table)) { continue; }
00110 
00111                 String edge_color = this._relationColor(this._db.getTableToTableRelationType(dependant_table, reference_table));
00112 
00113                 if (0 != dependant_table.getName().compareTo(reference_table.getName()))
00114                 {
00115                     // Create the edge from the reference table to the target table.
00116                     Edge join = new Edge();
00117                     join.setFrom(dependant_table.getName());
00118                     join.setTo(reference_table.getName());
00119                     join.setPenwidth("2");
00120                     join.setColor(edge_color);
00121                     join.setLtail(SubGraph.generateName(dependant_table.getName()));
00122                     join.setLhead(SubGraph.generateName(reference_table.getName()));
00123                     digraph.addEdge(join);
00124                 }
00125                 else
00126                 {
00127                     String middle_name = "l" + looper.toString();
00128                     looper += 1;
00129 
00130                     Node middle = new Node(middle_name);
00131                     middle.setShape("point");
00132                     digraph.addNode(middle);
00133 
00134                     Edge join1 = new Edge();
00135                     join1.setArrowhead("none");
00136                     join1.setFrom(dependant_table.getName());
00137                     join1.setTo(middle_name);
00138                     join1.setPenwidth("2");
00139                     join1.setColor(edge_color);
00140                     join1.setLtail(SubGraph.generateName(dependant_table.getName()));
00141                     digraph.addEdge(join1);
00142 
00143                     Edge join2 = new Edge();
00144                     join2.setFrom(middle_name);
00145                     join2.setTo(reference_table.getName());
00146                     join2.setPenwidth("2");
00147                     join2.setColor(edge_color);
00148                     join2.setLhead(SubGraph.generateName(reference_table.getName()));
00149                     digraph.addEdge(join2);
00150                 }
00151             }
00152         }
00153 
00154         return digraph.toString();
00155     }
00156 
00157     /**
00158      * This method creates the &quot;medium&quot; label for a given table. The label is a
00159      * grid that contains 5 columns, and as many row as the number of fields in
00160      * the table.
00161      *
00162      * @param in_table
00163      *            The table.
00164      * @param in_rankdir
00165      *            Initial orientation of a record node. Values can be:
00166      *            <ul>
00167      *               <li>TB (Top to bottom)</li>
00168      *               <li>LR (Left to right)</li>
00169      *               <li>RL 'Right to left)</li>
00170      *            </ul>
00171      * <p>See GRAPHVIZ' documentation for "rankdir": http://www.graphviz.org/doc/info/shapes.html</p>
00172      * @return The method returns a string that represents the label.
00173      */
00174     private String __createMediumTableLabel(Table in_table, String in_rankdir)
00175     {
00176         GridByRow label = new GridByRow();
00177         label.setRankdir(in_rankdir);
00178 
00179         // Create rows: {name}.
00180         for (Field field : in_table.getFields())
00181         {
00182             ArrayList<String> line = new ArrayList<String>();
00183 
00184             // Add the name of the field.
00185             line.add(field.getName());
00186 
00187             // Add the line to the label.
00188             label.add(line);
00189         }
00190 
00191         return label.toString();
00192     }
00193 }