You are here: Wiki>AGGeom Web>JavaView>JVCodingPractice (28 Apr 2017, ezimmermann)Edit

JVCodingPractice

Here you can find general advices how to structure your code and some dos and don'ts, especially when you are working with others together.

Style Guide

JavaView Code Preference Settings

If you have not yet synchronized your code style to JavaView standard, then simply import the JavaView code preference settings: Allow a unified code style and setting of warning and error levels Load into eclipse the file: JavaView-SVN/_eclipse/rsrc/javaview_javaCodeStylePrefs.epf using: File -> Import -> General -> Preferences Select the file and choose „import all“. (if you like, save your preferences before).

JavaDoc

  1. Add documentation to all your classes and methods!
  2. In version 2.99.010 the Javadoc section of the whole code was automatically formatted to have a uniform look of the javadoc tags. Now there are the following number of tabs (assuming tab==3 spaces) following each tag:
       @param      2
       @return     2
       @see        3
       @author     2
       @version    2
       @since      2
       @deprecated 1
          
  3. When documenting code use the following guidelines with respect to ordering of tags and formatting style when using any of the javadoc tags:
          @param      anArgument      describes an argument
          @return     a boolean value if no integer available
          @see        #method
          @author     Konrad Polthier and Mister Else
          @version    26.08.03, 1.10 revised (kp) Because of this reason.<br>
          @since      JavaView 2.99.002
         @deprecated since JavaView 2.99.002, use {@link #method method} instead.
       
  4. In contrast to the official guidelines of JavaDoc we use the author and version tag whenever a method is modified after the initial release of a class. Currently the author and version tag of methods will not appear in the documentation but our code will benefit.
  5. The current doc has no more broken Javadoc links. Some {@link ...} reference needed to be removed. Using {@link ... } to reference from a public method to a protected method is considered a WARNING by javadoc.
  6. Do not check-in any class or method with undocumented content. It just takes seconds...
  7. If a new method METH_NEW is created containing the (modified) body of an existing method METH_OLD then the documentation of both methods should keep respectively contain the version history of METH_NEW. Additional, new entries in each of the two methods should specify the current changes which have just been performed. This also applies if the method is kept but the signature is changed. For example, the version entry of METH_NEW could be:
         @version ... revised (xx) Method created using the body of METH_OLD<br>
         @since   JavaView 2.49.005
       
    and of METH_OLD :
         @version ... revised (xx) Body of method moved to METH_NEW"
       
    Do not forget the @since entry.

Naming Conventions

  1. All member variables of a class have a name like m_variable except public static variables which are written with capital letters and a blank between word components like GLOBAL_VARIABLE. All other variables are written without a special prefix and start with a lowercase letter: i, parm, geomSave, etc.
  2. Member variables may try to show their type which is especially useful in inspectors to use the same name related to similar things, for example:
       Panel pSolve     = new Panel()
       Label lSolve     = new Label("Type Problem");
       Textfield tSolve = new Textfield();
       pSolve.add(lSolve); 
       pSolve.add(tSolve);
       
On panels, use the first letter of the component. In other classes helpful namings are: boolean bShow. Instance variable will be named like m_bShow, m_pSolve etc.
  1. Boolean instance variables must be named like boolean m_bProperty instead of boolean hasProperty, property, ...
  2. Local variable should follow the same rule: boolean bProperty.
  3. Method names start with a lower case letter and do not include class names of arguments. Such methods are fully distinguished by their signature. Use protected void splitGeometry(geom, vLow); instead of protected void SplitGeometryAtBoolean(geom, vLow);.

Coding

  1. Inspectors should not contain public methods since the inspector should only be controlled via the base class with base.update(base). That is, whenever the inspector receives an update from its parent then it configures itself. A direct invocation of the inspector is against the rules since it circumvents the update mechanism. For example, in a base class the following statements are not ok:
          if (hasInspector(INSPECTOR_INFO)) {
          PsPanel pan = getInspector(INSPECTOR_INFO);
          ((Base_IP)pan).setMinimizing(false);
       }
       
    and correspondingly there should not be a public method in Base_IP: public void setMinimizing(boolean flag) {..}
  2. Use PsPanel.addLabelComponent() and PsPanel.addTextField() to reduce the amount of code in an inspector. Both methods create a horizonal panel in GridLayout(1,2) showing a label on the left and the component on the right, like
    [My own value         1.2222]
    Of course, this is only useful if the label will not change.
  3. To assign boolean variables use bState = (a < b); instead of
       if (a < b)
          bState = true;
       else
          bState = false;
       
  4. In info panels the method setParent(PsUpdateIf parent) must be implemented such that is can be called multiple times. Sometimes a panel obtained from an instance variable of the parent shall be inserted into this info panel. Proceed as follows:
       class PwTool_IP extends ... {
       protected    PwTool    m_tool;
       protected   Panel      m_pSomething;
       public PwTool_IP() {
          ...
          if (getClass() == PwTool_IP.class)
             super.init();      
       }
       public void init() {
          super.init();
          m_pSomething = new Panel();
          add(m_pSomething);
       }
       public void setParent(PsUpdateIf parent) {
          super.setParent(parent);
          m_tool = (PwTool)parent;
          m_pSomething.removeAll;
          m_pSomething.add(m_tool.getInstance().newInspector();
          m_pSomething.validate;
       }
       }
       
    The following trick is not allowed although the init() method has access to m_tool and could avoid the creation of the container panel:
       public void setParent(PsUpdateIf parent) {
          super.setParent(parent);
          m_tool = (PwTool)parent;
          // Not allowed:
          init(); 
       }
       

Unused Private Methods

Just uncomment those never used private methods. You save the day of someone who must at one day go through your code. Just disable unused code yourself.

References to panels and dialogs within data classes: For example, do not store infoPanel or dialog as reference within a workshop. These GUI stuff must reside outside the so-called data classes in order to allow the whole JavaView package to run in batch mode.

The Update Mechanism

Problem: The update(Object) method of objects should be called from less, selected places, especially not in methods, which fullfill calculations (compute-methods). Reason: If a compute-method calls an update() itself, it is not possible to implement it in the sequenece, whereas the object gets updated once in the end. If there would be a sequence compute1(), compute2(), ... etc., then every compute() method initializes an update().

Solution: Call update() in the actual public boolean udate(Object object) in general (with exceptions), or after user interaction with the panel or other events.

General strategy:
  • Use geom.update(null), to inform the parent of geom, that geom changed. This call initializes in PsObject a call m_parent.update(geom) and jumps to the update() method of parent. Furthermore use this command to update the geometry in the viewer. This call requieres, that geom and its panels are up to date. The following call does not make this requirement:
  • Use geom.update(geom) to first update the info/material/... panels after a change of geom . Afterwards geom.update(null) gets called automatically. The second case includes the first one. If the panels are not visible, they won't get updated (not until they become visible again). But when the info-panel is visible, then it gets always updated.
  • Use geom.update(other) when the object has changed and the geom should react. Then we have to ask in the update-method of geom if event==object. After geom was updated, the update can be passed to the super class of geom. Usually with the argument null or this, since geom is already up to date.
Geom {
    update(Object object) {
    if (object==other) {
        // bringe geom auf den neuesten Stand
        return super.update(null); // oder super.update(this)
    } else if (object== ...

An understanding of this mechanism is important when we write code, which serve others as a basis.

Do not send update events from computational method, for example, from static workshop methods which do a larger computation. The reason is that someone may use several of these methods to perform some calculation and may want to have control when an update is issued.

Also set-methods should rarely issue an update since a programmer may want to call several set-methods to configure a class and finally send a single update.

As a general rule (with exceptions), update events should be send from GUI panels or from an update methods. In this sense, update events are less often sent compared to GUI events. The following code is against the update philosophy for several reasons:
   public boolean update(Object event) {
      if (event == m_geom) {
(1)         m_infoPanel.update(m_geom);
         return true;
      } else if (event == m_infoPanel) {
(2)         return m_parent.update(this);
      } else {
(3)         return true;
      }
   }

ad (1): The info panel should not be directly accessed since there may exist a number of info panels of the same class being registered as inspectors of class, for example, by other developers. Therefore, use in (1) update(this). Of course, this will initiate many more updates, but the base class has changed and all depended classes must be informed about the changes.

ad (2): For the same reason do not check events of the inspector. In the early days of JavaView when each class contained only a single info panel, this was a recommended behaviour. Now each info panel should perform all necessary modifications of its parent class and then initiate from inside the inspector m_parent.update(null) or m_parent.update(m_parent) depending on whether other inspectors must be updated too.

Furthermore, the line (3) should also not access m_parent directly since a base class may have many more registered listeners. Therefore, replace line (2) with update(this);

ad (3): Directly returning from an update should be used with care. One never knows if the superclass might be interested in an update event about which this subclass does not know about. A superclass might not be interested now, but maybe after a future code modification. Therefore replace (3) with return super.update(event);

Never directly call update() from set / get / remove -methods. Don't do this:
   public void set(int index) {
      ....
      m_VF.update(null);
      m_bUpdateSender = true;
      m_pointSet.update(null);
      m_bUpdateSender = false;
      update(this);
   }
or that
   public void setCenterType(int centerIndex, int type) {
      ....
      update(m_centerIndex);
   }

The following code snippet contains 4 update() -calls :-((

   public update(...) {
      ....
      if (m_pointSet != null && m_VF != null) {
         calculateVF();
         m_VF.update(null);
         m_bUpdateSender = true;
         m_pointSet.update(null);
         m_bUpdateSender = false;
      }
      m_bUpdateSender = true;
      m_centers.update(m_centers);
      m_bUpdateSender = false;
      update(this); //instead of getting info panel and calling update directly
      ...
   }

Clone vs. Copy

clone() is a system routine implemented by all Java classes. Its purpose is to generate a new 1-1 duplicate object. Instance variables are copied automatically, instance objects require each an own clone-call. Some instance variables must be nulled, for example PsObject.clone() nulls m_parent since the clone has no parent yet.

copy() is a JavaView routine not available in Java. It is intended to copy a source object into an existing target object where target and source may not be 1:1 identical (for example, differences in maxNumVertices).

copy() is slightly different from clone(), for example:
  • m_parent of the target object will not be nulled.
  • A copy of instance variables is automatically done in clone()
and less efficient in copy().
  • PgPointSet#clone() creates a 1:1 copy while PgPointSet#copy() allocates target#setNumVertices,
so source.maxNumVertices >= targetmaxNumVertices.

Both methods are very similar but there are presently subtle differences between both methods.

MISC

  • In each applet the author must specify topic and author in method Applet.getAppletInfo(). This information is displayed in the ABOUT APPLET panel of each applet to be invoked with the menu Help -> About Applet.

  • Comment from JBuilder: Use frame.pack() for frames that contain information about the preferred size, e.g. from their layout. Use frame.validate() for frames that have a fixed, predefined size.

Comments

 
Topic revision: r7 - 28 Apr 2017, ezimmermann
 
  • Printable version of this topic (p) Printable version of this topic (p)