Browse Source

Millions of fixes, fixes for me
- Fixed hanging save on a Material definition file.
- Fixed Node editor blow up when changing a shader node definition content.
- Enhanced error reporting.
- and many more.

Nehon 10 years ago
parent
commit
2b75c5793e

+ 38 - 26
jme3-materialeditor/src/com/jme3/gde/materialdefinition/EditableMatDefFile.java

@@ -30,8 +30,8 @@ import com.jme3.util.blockparser.Statement;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -55,7 +55,7 @@ import org.openide.util.WeakListeners;
 public class EditableMatDefFile {
 
     private FileObject matDefFile;
-    private MatDefDataObject obj;
+    private final MatDefDataObject obj;
     private Material material;
     private MatDefBlock matDefStructure;
     private TechniqueBlock currentTechnique;
@@ -64,7 +64,7 @@ public class EditableMatDefFile {
 //    MatParamTopComponent matParamComponent;
     private ShaderGenerator glsl100;
     private ShaderGenerator glsl150;
-    private String selectedTechnique = "Default";
+    private final String selectedTechnique = "Default";
     private final static String GLSL100 = "GLSL100";
     private final static String GLSL150 = "GLSL150";
     private Lookup lookup;
@@ -78,6 +78,7 @@ public class EditableMatDefFile {
     }
 
     public final void load(Lookup lookup) {
+        loaded = false;
         this.matDefFile = obj.getPrimaryFile();
         this.assetManager = lookup.lookup(ProjectAssetManager.class);
         this.glsl100 = new Glsl100ShaderGenerator(assetManager);
@@ -92,20 +93,27 @@ public class EditableMatDefFile {
             obj.getLookupContents().remove(materialDef);
             materialDef = null;
         }
+        if (material != null) {
+            obj.getLookupContents().remove(material);
+            matToRemove = material;
+            material = null;
+        }
         FileLock lock = null;
+        InputStream in = null;
+        boolean matParseError = false;        
         try {
             lock = matDefFile.lock();
-            List<Statement> sta = BlockLanguageParser.parse(obj.getPrimaryFile().getInputStream());
+            in = obj.getPrimaryFile().getInputStream();
+            List<Statement> sta = BlockLanguageParser.parse(in);
             matDefStructure = new MatDefBlock(sta.get(0));
-            if(assetManager!=null){
+            if (assetManager != null) {
                 AssetKey<MaterialDef> matDefKey = new AssetKey<MaterialDef>(assetManager.getRelativeAssetPath(assetManager.getRelativeAssetPath(matDefFile.getPath())));
                 assetManager.deleteFromCache(matDefKey);
                 materialDef = (MaterialDef) assetManager.loadAsset(assetManager.getRelativeAssetPath(matDefFile.getPath()));
             }
-            lock.releaseLock();
         } catch (Exception ex) {
             Throwable t = ex.getCause();
-            boolean matParseError = false;
+
             while (t != null) {
                 if (t instanceof MatParseException) {
                     Logger.getLogger(EditableMatDefFile.class.getName()).log(Level.SEVERE, t.getMessage());
@@ -120,8 +128,15 @@ public class EditableMatDefFile {
             if (lock != null) {
                 lock.releaseLock();
             }
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
         }
-        if (materialDef != null) {
+        if (materialDef != null && !matParseError) {
             currentTechnique = matDefStructure.getTechniques().get(0);
             registerListener(matDefStructure);
 
@@ -164,8 +179,7 @@ public class EditableMatDefFile {
                 glsl150.initialize(material.getActiveTechnique());
                 s = glsl150.generateShader();
             }
-            for (Iterator<Shader.ShaderSource> it = s.getSources().iterator(); it.hasNext();) {
-                Shader.ShaderSource source = it.next();
+            for (Shader.ShaderSource source : s.getSources()) {
                 if (source.getType() == type) {
                     return source.getSource();
                 }
@@ -177,13 +191,6 @@ public class EditableMatDefFile {
         }
     }
 
-//    public MatParamTopComponent getMatParamComponent() {
-//        return matParamComponent;
-//    }
-//    
-//    public void setMatParamComponent(MatParamTopComponent matParamComponent) {
-//        this.matParamComponent = matParamComponent;
-//    }
     public TechniqueBlock getCurrentTechnique() {
         return currentTechnique;
     }
@@ -191,7 +198,7 @@ public class EditableMatDefFile {
     public MatDefBlock getMatDefStructure() {
         return matDefStructure;
     }
-    private MatStructChangeListener changeListener = new MatStructChangeListener();
+    private final MatStructChangeListener changeListener = new MatStructChangeListener();
     J3MLoader loader = new J3MLoader();
 
     private void updateLookupWithMaterialData(MatDefDataObject obj) {
@@ -202,7 +209,12 @@ public class EditableMatDefFile {
             material.selectTechnique("Default", SceneApplication.getApplication().getRenderManager());
             if (matToRemove != null) {
                 for (MatParam matParam : matToRemove.getParams()) {
-                    material.setParam(matParam.getName(), matParam.getVarType(), matParam.getValue());
+                    try {
+                        material.setParam(matParam.getName(), matParam.getVarType(), matParam.getValue());
+                    } catch (IllegalArgumentException ie) {
+                        matToRemove.clearParam(matParam.getName());
+                    }
+
                 }
                 obj.getLookupContents().remove(matToRemove);
                 matToRemove = null;
@@ -264,13 +276,13 @@ public class EditableMatDefFile {
                 for (ShaderNodeBlock shaderNodeBlock : currentTechnique.getShaderNodes()) {
 
                     if (shaderNodeBlock.getCondition() != null && shaderNodeBlock.getCondition().contains(oldValue.getName())) {
-                        shaderNodeBlock.setCondition(shaderNodeBlock.getCondition().replaceAll(oldValue.getName(), "").trim());                      
+                        shaderNodeBlock.setCondition(shaderNodeBlock.getCondition().replaceAll(oldValue.getName(), "").trim());
                     }
                     List<InputMappingBlock> lin = shaderNodeBlock.getInputs();
                     if (lin != null) {
                         for (InputMappingBlock inputMappingBlock : shaderNodeBlock.getInputs()) {
                             if (inputMappingBlock.getCondition() != null && inputMappingBlock.getCondition().contains(oldValue.getName())) {
-                                inputMappingBlock.setCondition(inputMappingBlock.getCondition().replaceAll(oldValue.getName(), "").trim());                               
+                                inputMappingBlock.setCondition(inputMappingBlock.getCondition().replaceAll(oldValue.getName(), "").trim());
                             }
                         }
                     }
@@ -278,7 +290,7 @@ public class EditableMatDefFile {
                     if (l != null) {
                         for (OutputMappingBlock outputMappingBlock : l) {
                             if (outputMappingBlock.getCondition() != null && outputMappingBlock.getCondition().contains(oldValue.getName())) {
-                                outputMappingBlock.setCondition(outputMappingBlock.getCondition().replaceAll(oldValue.getName(), "").trim());                             
+                                outputMappingBlock.setCondition(outputMappingBlock.getCondition().replaceAll(oldValue.getName(), "").trim());
                             }
                         }
                     }
@@ -303,10 +315,10 @@ public class EditableMatDefFile {
             NbDocument.runAtomicAsUser(ec.getDocument(), new Runnable() {
                 public void run() {
                     try {
-                        doc.remove(0, doc.getLength());
-                        doc.insertString(doc.getLength(),
-                                matDefStructure.toString(),
-                                SimpleAttributeSet.EMPTY);
+                    doc.remove(0, doc.getLength());
+                    doc.insertString(doc.getLength(),
+                    matDefStructure.toString(),
+                    SimpleAttributeSet.EMPTY);
                     } catch (BadLocationException e) {
                         exc[0] = e;
                     }

+ 74 - 52
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/MatDefEditorlElement.java

@@ -52,16 +52,20 @@ import com.jme3.shader.ShaderNodeVariable;
 import com.jme3.shader.ShaderUtils;
 import java.awt.Color;
 import java.awt.Dimension;
+import java.awt.Font;
 import java.awt.Point;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.beans.PropertyVetoException;
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import javax.swing.Action;
-import javax.swing.JButton;
 import javax.swing.JComponent;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
@@ -71,10 +75,12 @@ import org.netbeans.core.spi.multiview.MultiViewElement;
 import org.netbeans.core.spi.multiview.MultiViewElementCallback;
 import org.netbeans.core.spi.multiview.text.MultiViewEditorElement;
 import org.openide.awt.UndoRedo;
+import org.openide.cookies.EditorCookie;
 import org.openide.filesystems.FileObject;
 import org.openide.filesystems.FileUtil;
 import org.openide.nodes.Children;
 import org.openide.nodes.Node;
+import org.openide.text.EditorSupport;
 import org.openide.util.Exceptions;
 import org.openide.util.Lookup;
 import org.openide.util.LookupEvent;
@@ -85,12 +91,12 @@ import org.openide.util.lookup.InstanceContent;
 import org.openide.windows.TopComponent;
 
 @MultiViewElement.Registration(
-    displayName = "#LBL_MatDef_EDITOR",
-iconBase = "com/jme3/gde/materialdefinition/icons/matdef.png",
-mimeType = "text/jme-materialdefinition",
-persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
-preferredID = "MatDefVisual",
-position = 2000)
+        displayName = "#LBL_MatDef_EDITOR",
+        iconBase = "com/jme3/gde/materialdefinition/icons/matdef.png",
+        mimeType = "text/jme-materialdefinition",
+        persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
+        preferredID = "MatDefVisual",
+        position = 2000)
 @Messages("LBL_MatDef_EDITOR=Editor")
 public final class MatDefEditorlElement extends JPanel implements MultiViewElement {
 
@@ -100,7 +106,7 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme
     InstanceContent content;
     Selectable prevNode;
     MatDefMetaData metaData;
-    
+
     public MatDefEditorlElement(final Lookup lkp) {
         initComponents();
         obj = lkp.lookup(MatDefDataObject.class);
@@ -109,14 +115,14 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme
         final EditableMatDefFile file = obj.getEditableFile();
         shaderEditPanel1.setVisible(false);
         shaderEditPanel1.setParent(this);
-        reload(file, lkp);        
+        reload(file, lkp);
     }
 
     private void initDiagram(Lookup lkp) throws NumberFormatException {
-       
+
         diagram1.clear();
         diagram1.setParent(this);
-        
+
         Material mat = lkp.lookup(Material.class);
 
         ProjectAssetManager manager = obj.getLookup().lookup(ProjectAssetManager.class);
@@ -213,7 +219,6 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme
         diagram1.revalidate();
         jScrollPane1.addComponentListener(diagram1);
 
-
         diagram1.refreshPreviews(mat);
         final Lookup.Result<Material> resMat = obj.getLookup().lookupResult(Material.class);
         resMat.addLookupListener(new LookupListener() {
@@ -226,7 +231,6 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme
             }
         });
 
-
         final MatDefNavigatorPanel nav = obj.getLookup().lookup(MatDefNavigatorPanel.class);
         if (nav != null) {
 
@@ -267,7 +271,7 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme
             Exceptions.printStackTrace(ex);
         }
     }
-    
+
     public void refresh() {
 
         Lookup.Result<Material> resMat = obj.getLookup().lookupResult(Material.class);
@@ -278,32 +282,52 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme
         }
 
     }
-    
-    public void setModified(){
-        obj.setModified(true);        
+
+    public void setModified() {
+        obj.setModified(true);
     }
-    
-    public ProjectAssetManager getAssetManager(){
+
+    public ProjectAssetManager getAssetManager() {
         return obj.getLookup().lookup(ProjectAssetManager.class);
     }
-    
-    public void showShaderEditor(String nodeName,NodePanel.NodeType type,List<String>pathList){
-        
+
+    public void showShaderEditor(String nodeName, NodePanel.NodeType type, List<String> pathList) {
+
         List<FileObject> fos = new ArrayList<FileObject>();
-        for (String path : pathList) {            
-            FileObject text = FileUtil.toFileObject(new File(getAssetManager().getAbsoluteAssetPath(path)));
-            fos.add(text);
+        Map<String, String> readOnlyFiles = new HashMap<String, String>();
+        for (String path : pathList) {
+            try {
+                FileObject text = FileUtil.toFileObject(new File(getAssetManager().getAbsoluteAssetPath(path)));
+                fos.add(text);
+            } catch (NullPointerException e) {
+                try {
+                    //cannot load the files because they are probably in a jar
+                    InputStream is = getAssetManager().getResourceAsStream(path);
+                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+                    StringBuilder out = new StringBuilder();
+                    String line;
+                    while ((line = reader.readLine()) != null) {
+                        out.append(line).append("\n");
+                    }
+                    readOnlyFiles.put(path.substring(path.lastIndexOf("/") + 1), out.toString());   //Prints the string content read from input stream
+                    reader.close();
+                } catch (IOException ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+
+            }
+
         }
-        shaderEditPanel1.setFiles(nodeName, type, fos);
+        shaderEditPanel1.setFiles(nodeName, type, fos, readOnlyFiles);
         shaderEditPanel1.revalidate();
-        if(!shaderEditPanel1.isVisible() || jSplitPane.getDividerLocation() == jSplitPane.getMinimumDividerLocation()){
+        if (!shaderEditPanel1.isVisible() || jSplitPane.getDividerLocation() == jSplitPane.getMinimumDividerLocation()) {
             shaderEditPanel1.setVisible(true);
             jSplitPane.setDividerLocation(650);
         }
-        
+
     }
-    
-    public ShaderEditPanel getShaderEditor(){
+
+    public ShaderEditPanel getShaderEditor() {
         return shaderEditPanel1;
     }
 
@@ -496,13 +520,13 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme
     }
 
     public void notifyAddMapParam(String type, String name) {
-        MatDefBlock matDef = obj.getLookup().lookup(MatDefBlock.class);        
+        MatDefBlock matDef = obj.getLookup().lookup(MatDefBlock.class);
         MatParamBlock param = new MatParamBlock(type, name, null, null);
         matDef.addMatParam(param);
     }
 
     public void notifyAddWorldParam(String name) {
-        MatDefBlock matDef = obj.getLookup().lookup(MatDefBlock.class);        
+        MatDefBlock matDef = obj.getLookup().lookup(MatDefBlock.class);
         WorldParamBlock param = new WorldParamBlock(name);
         getTechnique(matDef).addWorldParam(param);
     }
@@ -596,7 +620,6 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme
 
         }
 
-
         for (WorldParamBlock worldParamBlock : technique.getWorldParams()) {
             ShaderNodeVariable var = new ShaderNodeVariable("", "WorldParam", worldParamBlock.getName());
             var.setType(MaterialUtils.getWorldParamType(var.getName()));
@@ -633,9 +656,15 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme
         metaData.setProperty(diagram1.getCurrentTechniqueName() + "/" + key, x + "," + y);
 
     }
-    
-    public void reload(){
-          reload(obj.getEditableFile(), obj.getLookup());
+
+    public void reload() {
+        try {
+            obj.getLookup().lookup(EditorCookie.class).saveDocument();
+            obj.getEditableFile().load(obj.getLookup());
+            reload(obj.getEditableFile(), obj.getLookup());
+        } catch (IOException ex) {
+            Exceptions.printStackTrace(ex);
+        }
     }
 
     private void reload(final EditableMatDefFile file, final Lookup lkp) throws NumberFormatException {
@@ -647,21 +676,14 @@ public final class MatDefEditorlElement extends JPanel implements MultiViewEleme
             }
         } else {
             diagram1.clear();
-            JLabel error = new JLabel("Cannot load material definition.");
-            error.setForeground(Color.RED);
-            error.setBounds(0, 0, 200, 20);
+            JLabel error = new JLabel("<html><center>Cannot load material definition.<br>Please see the error log and fix it in the text editor</center></html>");
+            error.setForeground(Color.ORANGE);
+            error.setFont(new Font("Arial", Font.BOLD, 24));
+            error.setBounds(0, 0, 400, 100);
+            jScrollPane1.getHorizontalScrollBar().setValue(0);
+            error.setLocation(jScrollPane1.getViewport().getWidth() / 2 - 200, jScrollPane1.getViewport().getHeight() / 2 - 50);
             diagram1.add(error);
-            JButton btn = new JButton("retry");
-            btn.addActionListener(new ActionListener() {
-                public void actionPerformed(ActionEvent e) {
-                    file.load(lkp);
-                    if (file.isLoaded()) {
-                        initDiagram(lkp);
-                    }
-                }
-            });
-            btn.setBounds(0, 25, 150, 20);
-            diagram1.add(btn);
+            diagram1.repaint();
 
         }
     }

+ 63 - 27
jme3-materialeditor/src/com/jme3/gde/materialdefinition/editor/ShaderEditPanel.java

@@ -13,8 +13,10 @@ import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.io.IOException;
 import java.util.List;
+import java.util.Map;
 import javax.swing.JPanel;
 import javax.swing.JToggleButton;
+import javax.swing.text.DefaultStyledDocument;
 import javax.swing.text.EditorKit;
 import org.openide.awt.UndoRedo;
 import org.openide.cookies.EditorCookie;
@@ -34,25 +36,26 @@ public class ShaderEditPanel extends JPanel {
     private DataObject currentDataObject = null;
     private MatDefEditorlElement parent = null;
     private UndoRedo.Manager undoRedoManager;
+    private final String MIME = "text/x-glsl";
 
     /**
      * Creates new form ShaderEditPanel
      */
     public ShaderEditPanel() {
         initComponents();
-        String mime = "text/x-glsl";
-        EditorKit ek = CloneableEditorSupport.getEditorKit(mime);
-        shaderEditorPane.setEditorKit(ek);
-        shaderEditorPane.setContentType(mime);
         
+        EditorKit ek = CloneableEditorSupport.getEditorKit(MIME);
+        shaderEditorPane.setEditorKit(ek);
+        shaderEditorPane.setContentType(MIME);
+
         shaderEditorPane.addKeyListener(new KeyListener() {
 
             public void keyTyped(KeyEvent e) {
             }
 
-            public void keyPressed(KeyEvent e) {                               
+            public void keyPressed(KeyEvent e) {
                 if ((e.getKeyCode() == KeyEvent.VK_S) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
-                    saveCurrent();                    
+                    saveCurrent();
                 }
             }
 
@@ -63,11 +66,12 @@ public class ShaderEditPanel extends JPanel {
 
     public void setParent(MatDefEditorlElement parent) {
         this.parent = parent;
-        undoRedoManager = (UndoRedo.Manager)parent.getUndoRedo();
+        undoRedoManager = (UndoRedo.Manager) parent.getUndoRedo();
     }
 
-    public void setFiles(String title, NodePanel.NodeType type, List<FileObject> fos) {
+    public void setFiles(String title, NodePanel.NodeType type, List<FileObject> fos, final Map<String, String> readOnlyFiles) {
 
+        
         headerText.setText(title);
         headerText.setIcon(Icons.getIconForShaderType(type));
         boolean firstItem = true;
@@ -75,7 +79,7 @@ public class ShaderEditPanel extends JPanel {
             buttonGroup1.remove((JToggleButton) component);
         }
         buttonPanel.removeAll();
-        buttonPanel.repaint();        
+        buttonPanel.repaint();
 
         for (FileObject fo : fos) {
             final Tab b = new Tab();
@@ -86,51 +90,83 @@ public class ShaderEditPanel extends JPanel {
                 b.addActionListener(new ActionListener() {
                     public void actionPerformed(ActionEvent e) {
                         saveCurrent();
-                        try {                            
-                            shaderEditorPane.setDocument(b.dataObject.getLookup().lookup(EditorCookie.class).openDocument());   
-                            undoRedoManager.discardAllEdits();
-                            shaderEditorPane.getDocument().addUndoableEditListener(undoRedoManager);
+                        try {
+                            switchEditableDoc(b);
                         } catch (IOException ex) {
                             Exceptions.printStackTrace(ex);
                         }
-                        currentDataObject = b.dataObject;
                     }
-
                 });
                 if (firstItem) {
-                    shaderEditorPane.setDocument(b.dataObject.getLookup().lookup(EditorCookie.class).openDocument());                    
-                    undoRedoManager.discardAllEdits();
-                    shaderEditorPane.getDocument().addUndoableEditListener(undoRedoManager);                    
-                    currentDataObject = b.dataObject;
+                    switchEditableDoc(b);
                     b.setSelected(true);
-                    firstItem = false;                    
+                    firstItem = false;
                 }
             } catch (IOException ex) {
                 Exceptions.printStackTrace(ex);
             }
+            buttonPanel.add(b);
+        }
 
+        for (String key : readOnlyFiles.keySet()) {
+            final Tab b = new Tab();
+            b.setText(key);
+            buttonGroup1.add(b);
+            final String theKey = key;
+            b.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    switchReadOnlyDoc(readOnlyFiles.get(theKey));
+                }
+
+            });
+            if (firstItem) {
+                switchReadOnlyDoc(readOnlyFiles.get(key));
+                b.setSelected(true);
+                firstItem = false;
+            }
             buttonPanel.add(b);
         }
 
     }
 
+    private void switchEditableDoc(Tab b) throws IOException {
+        if(currentDataObject != null){
+            currentDataObject.getLookup().lookup(EditorCookie.class).close();
+        }        
+        shaderEditorPane.setDocument(b.dataObject.getLookup().lookup(EditorCookie.class).openDocument());
+        undoRedoManager.discardAllEdits();
+        shaderEditorPane.getDocument().addUndoableEditListener(undoRedoManager);
+        shaderEditorPane.setEditable(true);
+        currentDataObject = b.dataObject;
+    }
+
+    private void switchReadOnlyDoc(String text) {
+        if(currentDataObject != null){
+            currentDataObject.getLookup().lookup(EditorCookie.class).close();
+        }
+        shaderEditorPane.setText(text);
+        undoRedoManager.discardAllEdits();
+        shaderEditorPane.setEditable(false);
+        currentDataObject = null;
+    }
+
     public void saveCurrent() {
         if (currentDataObject != null && currentDataObject.isModified()) {
             FileLock lock = null;
-            
+
             try {
                 currentDataObject.getLookup().lookup(EditorCookie.class).saveDocument();
                 currentDataObject.setModified(false);
-                if(currentDataObject.getPrimaryFile().getExt().equalsIgnoreCase("j3sn")){
-                    parent.reload();                            
-                }                   
+                if (currentDataObject.getPrimaryFile().getExt().equalsIgnoreCase("j3sn")) {
+                    parent.reload();
+                }
                 parent.refresh();
             } catch (DataObjectNotFoundException ex) {
                 Exceptions.printStackTrace(ex);
             } catch (IOException ex) {
                 Exceptions.printStackTrace(ex);
-            }finally{
-                if (lock!=null){
+            } finally {
+                if (lock != null) {
                     lock.releaseLock();
                 }
             }
@@ -139,7 +175,7 @@ public class ShaderEditPanel extends JPanel {
 
     private class Tab extends JToggleButton {
 
-        DataObject dataObject;      
+        DataObject dataObject;
     }
 
     /**

+ 11 - 3
jme3-materialeditor/src/com/jme3/gde/materials/MaterialPreviewRenderer.java

@@ -117,7 +117,7 @@ public class MaterialPreviewRenderer implements SceneListener {
                                         label.setIcon(Icons.error);
                                     }
                                 });
-                                Logger.getLogger(MaterialPreviewRenderer.class.getName()).log(Level.SEVERE, "Error rendering material{0}", e.getMessage());
+                                smartLog("Error rendering material{0}", e.getMessage());
                             }
                         }
                     });
@@ -126,10 +126,18 @@ public class MaterialPreviewRenderer implements SceneListener {
                 return mat;
             }
         });
-
     }
     
-      public Material reloadMaterial(Material mat) {
+    private int lastErrorHash = 0;
+    private void smartLog(String expText, String message){
+        int hash = message.hashCode();
+        if(hash != lastErrorHash){
+            Logger.getLogger(MaterialPreviewRenderer.class.getName()).log(Level.SEVERE, expText, message);
+            lastErrorHash = hash;
+        }
+    }
+    
+    public Material reloadMaterial(Material mat) {
        
         ((ProjectAssetManager)mat.getMaterialDef().getAssetManager()).clearCache();