0

I have a class called Model that I wanted to represent as JTable, I manged to do that through subclassing AbstractTableModel. my problem is how to listen to changes in data and update my model, I looked into many tutorials and I found out that they implement TableModelListener and use void tableChanged() method but that didn't work for, som how I couldn't go into tableChanged() method and do the manipulation that I wanted. Instead went into setValueAt() method and implemented the logic i want inside it and it worked but i had to implement TableModelListener interface and it's method tableChanged() with empty code which i don't understand why. I think I have a problem understanding how tableListener works.

    package model;

import java.util.ArrayList;

import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;

public class ModelsTable extends AbstractTableModel implements TableModelListener
{
    private String[] columnNames = { "Model",
                    "mac start", "mac end",
                    "host start", "host end",
                    "dn start" , "dn end",
                    "sn start" , "sn end"};

    private ModelsDictionary dictionary = ModelsDictionary.getModelsDictionary();
    public ModelsTable() 
    {
        this.addTableModelListener(this);

    }

    public void fireTableCellUpdated(int row, int col)
    {
        System.out.println(row + "" + col);
    }

    @Override
    public int getColumnCount() 
    {
        return columnNames.length;
    }
    @Override
    public int getRowCount() 
    {
        return dictionary.getAllModels().size();
    }
    public String getColumnName(int col) 
    {
        return columnNames[col];
   }
     @Override
     public void setValueAt(Object aValue, int row, int col) 
     {
         System.out.println(row + " " + col);
         Model model = dictionary.getAllModels().get(row);
         Model newModel;

         if(col == 0) 
         {
        newModel = new Model((String)aValue,model.getMacStart(),model.getMacEnd(),model.getHostStart(),model.getHostEnd(),model.getDnStart(),model.getDnEnd(),model.getSnStart(),model.getSnEnd());
             dictionary.updateModel(model,newModel);
         }
         else if(col == 1)
         {
             newModel = new Model(model.getNumber(),(String)aValue,model.getMacEnd(),model.getHostStart(),model.getHostEnd(),model.getDnStart(),model.getDnEnd(),model.getSnStart(),model.getSnEnd());
             dictionary.updateModel(model,newModel);
         }
         else if(col == 2)
         {
             newModel = new Model(model.getNumber(),model.getMacStart(),(String)aValue,model.getHostStart(),model.getHostEnd(),model.getDnStart(),model.getDnEnd(),model.getSnStart(),model.getSnEnd());
             dictionary.updateModel(model,newModel);
         }
         else if(col == 3)
         {
             newModel = new Model(model.getNumber(),model.getMacStart(),model.getMacEnd(),(String)aValue,model.getHostEnd(),model.getDnStart(),model.getDnEnd(),model.getSnStart(),model.getSnEnd());
             dictionary.updateModel(model,newModel);
         }
         else if(col == 4)
         {
             newModel = new Model(model.getNumber(),model.getMacStart(),model.getMacEnd(),model.getHostStart(),(String)aValue,model.getDnStart(),model.getDnEnd(),model.getSnStart(),model.getSnEnd());
             dictionary.updateModel(model,newModel);
         }
         else if(col == 5)
         {
             newModel = new Model(model.getNumber(),model.getMacStart(),model.getMacEnd(),model.getHostStart(),model.getHostEnd(),(String)aValue,model.getDnEnd(),model.getSnStart(),model.getSnEnd());
             dictionary.updateModel(model,newModel);
         }
         else if(col == 6)
         {
             newModel = new Model(model.getNumber(),model.getMacStart(),model.getMacEnd(),model.getHostStart(),model.getHostEnd(),model.getDnStart(),(String)aValue,model.getSnStart(),model.getSnEnd());
             dictionary.updateModel(model,newModel);
         }
         else if(col == 7)
         {
             newModel = new Model(model.getNumber(),model.getMacStart(),model.getMacEnd(),model.getHostStart(),model.getHostEnd(),model.getDnStart(),model.getDnEnd(),(String)aValue,model.getSnEnd());
             dictionary.updateModel(model,newModel);
         }
         else if(col == 8)
         {
             newModel = new Model(model.getNumber(),model.getMacStart(),model.getMacEnd(),model.getHostStart(),model.getHostEnd(),model.getDnStart(),model.getDnEnd(),model.getSnStart(),(String)aValue);
             dictionary.updateModel(model,newModel);
         }      
     }
    @Override
    public Object getValueAt(int x, int y) 
    {

         Model model = dictionary.getAllModels().get(x);

         switch(y) {
         case 0:
              return model.getNumber();
         case 1:
              return model.getMacStart();
         case 2:
              return model.getMacEnd();
         case 3:
              return model.getHostStart();
         case 4:
              return model.getHostEnd();
         case 5:
             return model.getDnStart();
         case 6:
             return model.getDnEnd();
         case 7:
             return model.getSnStart();
         case 8: 
             return model.getSnStart();
         default:
             return "unknown";

         }
    }
    public boolean isCellEditable(int row, int col) 
    {
        return true;
    }

    @Override
    public void tableChanged(TableModelEvent event) 
    {
        System.out.println("lol");
        int row = event.getFirstRow();
        int column = event.getColumn();
        ModelsTable model = (ModelsTable)event.getSource();
        String columnName = model.getColumnName(column);
        Model data = (Model) model.getValueAt(row, column);
        System.out.println(model);
    }
}

and this is the panel that im showing the JTable in it package view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.ArrayList;

import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import Control.InteractiveTableModelListener;

import model.Model;
import model.ModelsDictionary;
import model.ModelsTable;
import net.miginfocom.swing.MigLayout;

public class AllModelsPanel extends JPanel 
{

    private boolean DEBUG = false;
    public AllModelsPanel()
    {
         super(new GridLayout(1, 0));

         ArrayList<Model> models = ModelsDictionary.getModelsDictionary().getAllModels();
         JTable table = new JTable();
         table.setModel(new ModelsTable());
         table.setPreferredScrollableViewportSize(new Dimension(500, 70));
         table.setFillsViewportHeight(true);

         JScrollPane scrollPane = new JScrollPane(table);
         add(scrollPane);


    }



}

and this is my ModelsDictionary class which aggregate Model class to add fuctionalties like reading/writing to DB or Files ** note: i'm using singelton design pattern.

package model;
import java.io.File;
import java.util.ArrayList;




import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


public class ModelsDictionary 
{

    private static ModelsDictionary myInstance;
    private ArrayList<Model> models = new ArrayList<Model>();
    private ArrayList<String> modelNumbers = new ArrayList<String>();


    private ModelsDictionary()
    {
        readXMLfile();
    }
    public static ModelsDictionary getModelsDictionary()
    {
        if (myInstance == null )
        {
            synchronized(ModelsDictionary.class)
            {
                if( myInstance == null)
                {
                    myInstance = new ModelsDictionary();
                }
            }
        }
        return myInstance;
    }

    public void addModel(Model model)
    {
        models.add(model);
        modelNumbers.add(model.getNumber());
        writeXMLfile();
    }
    public void deleteModel(Model model)
    {
        models.remove(model);
        modelNumbers.remove(model.getNumber());
    }
    public void updateModel(Model oldModel, Model newModel)
    {
        int index = models.indexOf(oldModel);
        System.out.println("index" + index);
        models.set(index, newModel);
        writeXMLfile();
    }
    public Model getModel(String modelNumber)
    {
        //System.out.println("getModels ,,,, models size: " +models.size());
        for(Model model: models)
        {
            //System.out.println("in models");
            if(model.getNumber().equals(modelNumber))
            {
                //System.out.println("model number matched");
                return model;
            }
        }
        return null;
    }
    public ArrayList<Model> getAllModels()
    {
        return models;
    }
    public ArrayList<String> getAllModelNumbers()
    {
        return modelNumbers;
    }
    public void readXMLfile()
    {
        models = new ArrayList<Model>();
        try 
        {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            File file = new File("models.xml");
            if(file.exists())
            {
                Document doc = dBuilder.parse(file);
                doc.getDocumentElement().normalize();
                NodeList nList = doc.getElementsByTagName("Model");
                for (int i = 0; i < nList.getLength(); i++)
                {
                    Node nNode = nList.item(i);
                    if (nNode.getNodeType() == Node.ELEMENT_NODE) 
                    {
                        Element eElement = (Element)nNode;
                        String number = eElement.getElementsByTagName("Number").item(0).getTextContent();
                        String macStart = eElement.getElementsByTagName("MacStart").item(0).getTextContent();
                        String macEnd = eElement.getElementsByTagName("MacEnd").item(0).getTextContent();
                        String hostStart = eElement.getElementsByTagName("HostStart").item(0).getTextContent();
                        String hostEnd = eElement.getElementsByTagName("HostEnd").item(0).getTextContent();
                        String snStart = eElement.getElementsByTagName("SnStart").item(0).getTextContent();
                        String snEnd = eElement.getElementsByTagName("SnEnd").item(0).getTextContent();
                        String dnStart = eElement.getElementsByTagName("DnStart").item(0).getTextContent();
                        String dnEnd = eElement.getElementsByTagName("DnEnd").item(0).getTextContent();

                        Model model = new Model(number);
                        model.setMacPatt(macStart, macEnd);
                        model.setDnPatt(dnStart, dnEnd);
                        model.setSnPatt(snStart, snEnd);
                        model.setHostPatt(hostStart, hostEnd);
                        addModel(model);    
                    }
                 }
            }

        } 
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
    public void writeXMLfile()
    {
        try
        {
                DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
                Document doc = docBuilder.newDocument();

                Element rootElement = doc.createElement("Models");
                doc.appendChild(rootElement);
                for(Model model : models)
                {
                    Element m = doc.createElement("Model");
                    rootElement.appendChild(m);


                    Element number = doc.createElement("Number");
                    number.setTextContent(model.getNumber());
                    m.appendChild(number);


                    Element macStart = doc.createElement("MacStart");
                    macStart.setTextContent(model.getMacStart());
                    m.appendChild(macStart);

                    Element macEnd = doc.createElement("MacEnd");
                    macEnd.setTextContent(model.getMacEnd());
                    m.appendChild(macEnd);

                    Element hostStart = doc.createElement("HostStart");
                    hostStart.setTextContent(model.getHostStart());
                    m.appendChild(hostStart);

                    Element hostEnd = doc.createElement("HostEnd");
                    hostEnd.setTextContent(model.getHostEnd());
                    m.appendChild(hostEnd);

                    Element dnStart = doc.createElement("DnStart");
                    dnStart.setTextContent(model.getDnStart());
                    m.appendChild(dnStart);

                    Element dnEnd = doc.createElement("DnEnd");
                    dnEnd.setTextContent(model.getDnEnd());
                    m.appendChild(dnEnd);

                    Element snStart = doc.createElement("SnStart");
                    snStart.setTextContent(model.getSnStart());
                    m.appendChild(snStart);

                    Element snEnd = doc.createElement("SnEnd");
                    snEnd.setTextContent(model.getSnEnd());
                    m.appendChild(snEnd);
                }
                TransformerFactory transformerFactory = TransformerFactory.newInstance();
                Transformer transformer = transformerFactory.newTransformer();
                transformer.setOutputProperty(OutputKeys.INDENT, "yes");
                transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
                DOMSource source = new DOMSource(doc);
                File file = new File("models.xml");
                StreamResult result = new StreamResult(file);

                transformer.transform(source, result);

        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}

the question is: i'm I doing this the right way because i intend to add more functionalties like add row and remove row. because it seems the code is working to edit cells by just using the setValueAt() method only and i don't how or why

  • 1
    Did you read [this](http://docs.oracle.com/javase/tutorial/uiswing/events/tablemodellistener.html)? – m0skit0 Jul 23 '13 at 17:03
  • Did you heard about Single Responsability principle? your model is the subject and the observer , you should consider refactoring and separate responsabilities, by the way you are breaking the contract when you override `fireCellUpdated(...)` – nachokk Jul 23 '13 at 17:12
  • yep I should do refactoring my problem that nothing is calling fireCellUpdated() or tableChanged() the only thing that is called is setValueAt() – Moayad Al-sowayegh Jul 23 '13 at 17:15
  • when you edit is call setValueAt() and then in that method at finish `fireTableCellUpdated(..)` you have to add – nachokk Jul 23 '13 at 17:18

1 Answers1

1

You should think in refactoring your AbstractTableModel implementation.It is the Subject and his own Observer has no much sense. You should separate responsabilities (Single Responsability Principle).

In your code, when you edit a cell setValueAt(Object value,int row,int col) is called.

     @Override
     public void setValueAt(Object aValue, int row, int col) 
     {
          //your default code here
           and then you should call 
           fireTableRowsUpdated(row,row); // if you change the row
           OR
           fireTableCellUpdated(row,col); // if you change the cell
           OR
           fireTableDataChanged(); // if you change all the model  

     }

I have a similar issue here,

Community
  • 1
  • 1
nachokk
  • 14,363
  • 4
  • 24
  • 53
  • ok, but one more point if I manged to make it run without calling fireTableCellUpdated() why do i need to call it ? and do i need to override it ? – Moayad Al-sowayegh Jul 23 '13 at 17:28
  • no, it depends of your needs but i never override fireTableCellUpdated .. you register your addTableModelListener, you need to call it cause your are notifying your observers that the cell changes.. is the `Observer Pattern` – nachokk Jul 23 '13 at 17:33