Create a Project based on P2P/PubSub with OODB and DataMining - IconPanel

Joe

Thành viên VIP
21/1/13
3,074
1,344
113
(Continue of HERE)

Create a Project based on P2P/PubSub with OODB and DataMining - IconPanel

ModelWorker
is always started by its master, the Subscriber. The passed parameters are the common POJO Parms and the received UDP-Packet from any unknown Publisher (MulticastSocket). With the UDP-Packet ModelWorker is able to identify the purpose of Publisher whether it must process the Packet or can ignore it. And that is, for example, in the following snippet:
Java:
      // parse the UDP-Packet to String[5]
      // where msg[0]: unique NetID
      //       msg[1]: Affected OODB Name
      //       msg[2]: Key or KeyList
      //       msg[3]: Model/JTable index
      //       msg[4]: Mode: 0 for update, 1 for add and 2 for delete

1     msg = (new String(packet.getData(), 0, packet.getLength())).split("\t");
      ...

      // sales, multiple keys ?
      // if it is, parse the Key-String to keys[]

2     if (key.charAt(0) == '\r') {
3       String[][] rows = P.models[0].getRows();
4       String[] keys = key.substring(1).split("\r");
        // update the rows of ListTableModel
5       for (String k:keys) {
6         Object obj = P.oodb.readLock(dbName, k);
7         int i = P.models[0].getRowAt(k);
8         rows[i] = ((Item)obj).toArray();
        }
        // update the Sales JTable
9       P.models[0].updateModel(rows);
10      if (P.icon) P.iPanel.reload( );
11      if (P.cate == 4) P.models[4].updateModel(rows);
        return;
    }
    ...
Explanation:
  • line 1: parse the UDP packet to String[5]
  • line 2..3: if Key-Sequence, parse key-sequence to Keys[]
  • line 5..8: reload the updated rows
  • line 9: Update JTable of Subscriber with index 0
  • line 10: Update IconPanel if Subcsriber prefers IconPanel presentation
  • line 11: Update JTable of Subscriber with index 4 if online
You may notice that the parsing bases either on the special character TAB (\t, line 1) within the received UDP message, or on the special character CarriageReturn (\r, line 2 and 4) if the key-String is a sequence of several keys separated by this \r. The PubSub Trick is the convened Multicasting Message format. Without such a fixed convention it is impossible for the Subscribers to distinguish the purpose of the received messages from different Publishers. And based on the UDP-Messages ModelWorker is able to actualize the online JTable/ListTableModel (refer THIS Session for the source) and/or the online IconPanel in real time (even if the latency times on the net are NOT negligible).


IconPanel

The registered Online Clients and the Sales staff have the choice to work with JTable or IconPanel by setting <SALE_ICON> YES /> in the Customer_config.txt or Boutique_config.txt. As I have explained to you in the previous sessions about the resizing of images. The IconPanel works with this technique:
Java:
1     BufferedImage img = Utilities.toImage(pic);
2     JButton but = null;
3     int w = 100, h = 70;
4     if (img == null) {
5       but = new JButton("NO IMAGE");
6       but.setPreferredSize(new Dimension(100, 70));
7     } else { // Minimizing the Images
8       w = img.getWidth();
9       h = img.getHeight();
10      double ratio = 0.2; // resizing the image
11      while (Math.ceil(h*ratio) > 70) ratio -= 0.005;
12      if (ratio == 0.2) while (Math.ceil(w*ratio) > 100) ratio -= 0.005;
13      w = (int)(Math.ceil(w*ratio));
14      h = (int)(Math.ceil(h*ratio)); if (h < 70) h = 70;
15      Image image = img.getScaledInstance(w, h, Image.SCALE_SMOOTH);
16      img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
17      img.getGraphics().drawImage(image, 0, 0 , null);
18      but = new JButton(new ImageIcon(img));
       }
Explanation:
  • line 1: create a BufferedImage from the String "pic"
  • line 5..6: in case of bad string pic (should never happen)
  • line 11: find the ratio based on the image height
  • line 12: if the height is unscalable, find the ratio based on the width
  • line 14: set min. height for the iconizing image
  • line 15..17: create an image based on the the scaled height and width
  • line 18: create a JButton with the created image
The String pic can be either an URL or a "serialized" image String (refer THIS Session for details). The Serialized Image String is in reality the true image of any known format (jpg, png, gif, etc.) and is independent from the physical location of the original image file. This technique enables the developers to store images as serialized object in an OODB. However, image is usually big, very big. To save space the image should URLized so that the serialized object is merely a String of a link. Much smaller than the Serialized Image String. The drawback is however the long access over the web instead of from an OODB.

The pop-up image is based on JDialog.
Java:
public class Show extends JDialog {
  public Show(String header, Object obj) {
    setTitle(header);
    JPanel jp = new JPanel( );
    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    if (obj instanceof JTextArea)
      ((JTextArea)obj).setEditable(false);
    else obj = getButton(obj);
    jp.add((JComponent) obj);
    add(jp, BorderLayout.CENTER);
    setLocation(100, 50);
    pack();
  }
  private JButton getButton(Object obj) {
    JButton but = null;
    if (obj instanceof String) {
      BufferedImage img = Utilities.toImage((String)obj);
      if (img == null) {
        but = new JButton("NO IMAGE");
        but.setPreferredSize(new Dimension(200, 200));
      } else { // reduce the size?
        double ratio = 1d;
        int w = img.getWidth();
        int h = img.getHeight();
        // resizing the image ?
        if (h > 900)  ratio = 0.40d;
        else if (h > 800)  ratio = 0.45d;
        else if (h > 600)  ratio = 0.55d;
        else if (h > 500)  ratio = 0.6d;
        if (ratio == 1d) {
          if (w > 800) ratio = 0.6d;
          else if (w > 700) ratio = 0.7d;
        }
        if (ratio < 1d) {
          w = (int)Math.ceil(w * ratio);
          h = (int)Math.ceil(h * ratio);
          Image image = img.getScaledInstance(w, h, Image.SCALE_SMOOTH);
          img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
          img.getGraphics().drawImage(image, 0, 0 , null);
        }
        but = new JButton(new ImageIcon(img));
      }
    } else but = (JButton) obj;
    but.addActionListener(e -> {
      dispose();
      return;
    });
    getRootPane().setDefaultButton(but);
    return but;
  }
}
And here, too. The getButton(Object obj) checks for the given object whether it is a JButton or a String. In case of a String the BuffereredImage conversion will be made and the image will be reduced to min. 0.40% of the original size if the image is too large. Otherwise the original size is kept.
Java:
   BufferedImage img = Utilities.toImage((String)obj);
   ...
   if (h > 900)  ratio = 0.40d;
   else if (h > 800)  ratio = 0.45d;
   else if (h > 600)  ratio = 0.55d;
   else if (h > 500)  ratio = 0.6d;
   if (ratio == 1d) {
     if (w > 800) ratio = 0.6d;
     else if (w > 700) ratio = 0.7d;
   }
The full source of IconPanel.java
Java:
// Joe Nartca (C)
public class IconPanel extends JPanel {
  public IconPanel(Parms P) {
    this.P = P;
    setLayout(null);
    try {
      next = new JButton(new ImageIcon(ImageIO.read(getClass().getResourceAsStream("next.png"))));
      back = new JButton(new ImageIcon(ImageIO.read(getClass().getResourceAsStream("back.png"))));
    } catch (Exception ex) {
      next = new JButton(">> NEXT");
      back = new JButton("<< BACK");
    }
    back.addActionListener(e -> {
      int s = loc.size() - 1;
      cPos = s > 0? loc.get(s-1):0;
      pos = loc.get(s);
      load( );
    });
    next.addActionListener(e -> {
      loc.add(cPos);
      cPos = pos;
      load( );
    });
    rows = P.models[0].getRows();
    buts = new ArrayList<>(rows.length);
    for (int i = 0; i < rows.length; ++i) buts.add(button(i));
    load( ); // populate the IconPanel
  }
  public void addIcon(int idx) {
    rows = P.models[0].getRows();
    buts.add(button(idx));
    pos = cPos;
    load( );
  }
  public void delIcon(int idx) {
    buts.remove(idx);
    rows = P.models[0].getRows();
    pos = cPos;
    load( );
  }
  public void updateIcon(int idx) {
    buts.set(idx, button(idx));
    pos = cPos;
    load( );
  }
  public int getRow() {
    int r = row;
    row = -1;
    return r;
  }
  private void load( ) {
    lx = 0;
    row = -1;
    removeAll();
    int x = 10, y = 10, w;
    if (pos > 0) {
      back.setBounds(10, 10, 100, 70);
      add(back);
      x = 115;
    }
    for (; pos < rows.length; ++pos) {
      JButton but = buts.get(pos);
      add(but); // add to IconPanel
      Dimension dem = but.getPreferredSize();
      w = (int) dem.getWidth(); // Button width
      but.setBounds(x, y, w, (int) dem.getHeight());
      x += (w + 5); // next X position
      w = (pos+1) >= rows.length? 0:(int)buts.get(pos+1).getPreferredSize().getWidth();
      if (x > 900|| (995-x) < w) {
       y += 75;
       x = 10;
      }
      if (y > 300) {
        next.setBounds(x, y, 100, 70);
        add(next);
        break;
      }
    }
    lx = y > 300?10:x;
    revalidate();
    repaint();
  }
  private JButton button(int r) {
    String pic = rows[r][4];
    BufferedImage img = Utilities.toImage(pic);
    JButton but = null;
    int w = 100, h = 70;
    if (img != null) {
      w = img.getWidth();
      h = img.getHeight();
      double ratio = 0.2; // resizing the image
      while (Math.ceil(h*ratio) > 70) ratio -= 0.01;
      if (ratio == 0.2) while (Math.ceil(w*ratio) > 100) ratio -= 0.01;
      w = (int)(Math.ceil(w*ratio));
      h = (int)(Math.ceil(h*ratio)); if (h < 70) h = 70;
      Image image = img.getScaledInstance(w, h, Image.SCALE_SMOOTH);
      img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
      img.getGraphics().drawImage(image, 0, 0 , null);
      but = new JButton(new ImageIcon(img));
    } else but = new JButton("NO IMAGE");
    but.addActionListener(e -> {
      row = buts.indexOf((JButton)e.getSource());
      (new Show(rows[row])).setVisible(true);
      return;
    });
    but.setPreferredSize(new Dimension(w, h));
    return but;
  }
  private Parms P;
  private String[][] rows;
  private JButton next, back;
  private ArrayList<JButton> buts;
  private int row = -1, pos = 0, cPos = 0, lx;
  private ArrayList<Integer> loc = new ArrayList<>();
}
Note: the following code segment:
Java:
      next = new JButton(new ImageIcon(ImageIO.read(getClass().getResourceAsStream("next.png"))));
      back = new JButton(new ImageIcon(ImageIO.read(getClass().getResourceAsStream("back.png"))));
creates an image from ImageIO.read in conjunction with getClass().getResourceAsStream(). The reason is if the images are JARred together with the codes the images will be taken from the JAR file. Example:
Code:
jar -cvfme boutique.jar manifest.mf Boutique *.class *.png > ../log.txt
Explanation: -cvfme stands for C(reate), V(erbose), F(ile), M(anifest), E(entry). In plain English: all files with the suffix .class and .png should be JARred using the manifest file with the entry name Boutique and create a JAR file named boutique.jar

And the manifest.mf file that includes the OODB jar file:
Code:
Manifest-Version: 1.0
Class-Path: clientODB.jar
Created-By: 1.0.0 (Joe T. Nartca)
The invocation:
invocation.png

(continue HERE)
 
Sửa lần cuối: