//--------------------------------------------------------------------------------// // COPYRIGHT NOTICE // //--------------------------------------------------------------------------------// // Copyright (c) 2012, Instituto de Microelectronica de Sevilla (IMSE-CNM) // // // // All rights reserved. // // // // Redistribution and use in source and binary forms, with or without // // modification, are permitted provided that the following conditions are met: // // // // * Redistributions of source code must retain the above copyright notice, // // this list of conditions and the following disclaimer. // // // // * Redistributions in binary form must reproduce the above copyright // // notice, this list of conditions and the following disclaimer in the // // documentation and/or other materials provided with the distribution. // // // // * Neither the name of the IMSE-CNM nor the names of its contributors may // // be used to endorse or promote products derived from this software // // without specific prior written permission. // // // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE // // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // //--------------------------------------------------------------------------------// package xfuzzy.xfedit; import xfuzzy.lang.*; import xfuzzy.util.*; import javax.swing.*; import javax.swing.event.*; import java.awt.*; import java.awt.event.*; /** * Ventana de edici�n de un tipo de variable ling��stica * * @author Francisco Jos� Moreno Velo * */ public class XfeditTypeEditor extends JDialog implements ActionListener, MouseListener, KeyListener, ListSelectionListener, ListCellRenderer, WindowListener { /** * C�digo asociado a la clase serializable */ private static final long serialVersionUID = 95505666603041L; //----------------------------------------------------------------------------// // MIEMBROS PRIVADOS // //----------------------------------------------------------------------------// /** * Referencia a la aplicaci�n Xfedit que realiza la llamada al objeto */ private Xfedit xfeditor; /** * Sistema difuso a editar */ private Specification spec; /** * Referencia al tipo original a editar */ private Type original; /** * Copia de trabajo del tipo original a editar */ private Type copy; /** * Correpondencia entre el tipo original y la copia de trabajo */ private XfeditTypeMapping mapping[]; /** * Campos de texto para introducir datos */ private XTextForm dataform[]; /** * Lista de funciones de pertenencia del tipo */ private XList mflist; /** * Lista de familias de funciones del tipo */ private XList famlist; /** * Men� desplegable asociado a las funciones de pertenencia */ private JPopupMenu mfpopup; /** * Men� desplegable asociado a las familias */ private JPopupMenu fampopup; /** * Representaci�n gr�fica del tipo en edici�n */ private XfeditTypeGraphPanel graph; //----------------------------------------------------------------------------// // CONSTRUCTOR // //----------------------------------------------------------------------------// /** * Constructor */ public XfeditTypeEditor(Xfedit xfeditor, Type type){ super(xfeditor,"Xfedit",false); this.xfeditor = xfeditor; this.spec = xfeditor.getSpecification(); this.original = type; this.original.setEditing(true); getCopy(); build(); refresh(); } //----------------------------------------------------------------------------// // M�TODOS P�BLICOS EST�TICOS // //----------------------------------------------------------------------------// /** * Abre una ventana de edici�n de tipos */ static void showTypeEditor(Xfedit xfeditor, Type type) { XfeditTypeEditor editor = new XfeditTypeEditor(xfeditor,type); editor.setVisible(true); editor.repaint(); } //----------------------------------------------------------------------------// // M�TODOS P�BLICOS // //----------------------------------------------------------------------------// /** * Obtiene la referencia de la ventana principal */ public Xfedit getXfedit() { return this.xfeditor; } /** * Obtiene la copia de trabajo del tipo editado */ public Type getWorkingCopy() { return this.copy; } /** * A�ade una MF en la copia de trabajo del tipo */ public void addMF(LinguisticLabel newmf) { LinguisticLabel mf[] = copy.getMembershipFunctions(); LinguisticLabel amf[] = new LinguisticLabel[mf.length+1]; System.arraycopy(mf,0,amf,0,mf.length); amf[mf.length] = newmf; copy.setMembershipFunctions(amf); XfeditTypeMapping amp[] = new XfeditTypeMapping[mapping.length+1]; System.arraycopy(mapping,0,amp,0,mapping.length); amp[mapping.length] = new XfeditTypeMapping(null,newmf); this.mapping = amp; setMFList(); refresh(); } /** * Sustituye una MF en la copia de trabajo del tipo */ public void exchangeMF(LinguisticLabel oldmf, LinguisticLabel newmf) { LinguisticLabel mf[] = copy.getMembershipFunctions(); for(int i=0; i<mf.length; i++) if(mf[i] == oldmf) mf[i] = newmf; for(int i=0; i<mapping.length; i++) if(mapping[i].copy == oldmf) mapping[i].copy = newmf; copy.setMembershipFunctions(mf); setMFList(); refresh(); } /** * A�ade una familia en la copia de trabajo del tipo */ public void addFamily(Family newfam) { Family fam[] = copy.getFamilies(); Family af[] = new Family[fam.length+1]; System.arraycopy(fam,0,af,0,fam.length); af[fam.length] = newfam; copy.setFamilies(af); setFamilyList(); } /** * Sustituye una familia en la copia de trabajo del tipo */ public void exchangeFamily(Family oldfam, Family newfam) { Family fam[] = copy.getFamilies(); for(int i=0; i<fam.length; i++) if(fam[i] == oldfam) fam[i] = newfam; copy.setFamilies(fam); FamiliarMemFunc fmf[] = copy.getFamiliarMembershipFunctions(); for(int i=0; i<fmf.length; i++) { if(fmf[i].getFamily()==oldfam) fmf[i].setFamily(newfam); } setFamilyList(); } /** * Interfaz ActionListener */ public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if(command.equals("Ok")) { if(apply()) cancel(); } else if(command.equals("Apply")) apply(); else if(command.equals("Reload")) { getCopy(); refresh(); } else if(command.equals("Cancel")) cancel(); else if(command.equals("Name")) textAction(0); else if(command.equals("Minimum")) textAction(1); else if(command.equals("Maximum")) textAction(2); else if(command.equals("Cardinality")) textAction(3); else if(command.equals("RemoveFamily")) removeFamily(); else if(command.equals("NewFamily")) newFamily(); else if(command.equals("EditFamily")) editFamily(); else if(command.equals("RemoveMF")) removeMF(); else if(command.equals("NewMF")) newMF(); else if(command.equals("EditMF")) editMF(); } /** * Interfaz KeyListener - Acci�n de soltar una tecla */ public void keyReleased(KeyEvent e) { if(e.getComponent() == famlist.getList()) { if(e.getKeyCode() == KeyEvent.VK_DELETE) { e.consume(); removeFamily(); } if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { e.consume(); removeFamily(); } if(e.getKeyCode() == KeyEvent.VK_INSERT) { e.consume(); newFamily(); } if(e.getKeyCode() == KeyEvent.VK_ENTER) { e.consume(); editFamily(); } if(e.getKeyCode() == 226) { e.consume(); editFamily(); } } else { if(e.getKeyCode() == KeyEvent.VK_DELETE) { e.consume(); removeMF(); } if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { e.consume(); removeMF(); } if(e.getKeyCode() == KeyEvent.VK_INSERT) { e.consume(); newMF(); } if(e.getKeyCode() == KeyEvent.VK_ENTER) { e.consume(); editMF(); } if(e.getKeyCode() == 226) { e.consume(); editMF(); } } } /** * Interfaz KeyListener - Acci�n de presionar una tecla */ public void keyPressed(KeyEvent e) { } /** * Interfaz KeyListener - Acci�n de pulsar una tecla */ public void keyTyped(KeyEvent e) { } /** * Interfaz MouseListener - Acci�n de pulsar un bot�n del rat�n */ public void mouseClicked(MouseEvent e) { if(e.getComponent() == famlist.getList()) { if(e.getClickCount() == 2) { editFamily(); } } else { if(e.getClickCount() == 2) { editMF(); } } } /** * Interfaz MouseListener - Acci�n de presionar un bot�n del rat�n */ public void mousePressed(MouseEvent e) { if(!e.isPopupTrigger()) return; if(e.getComponent() == famlist.getList()) fampopup.show((Component) e.getSource(), e.getX(), e.getY()); else mfpopup.show((Component) e.getSource(), e.getX(), e.getY()); } /** * Interfaz MouseListener - Acci�n de soltar un bot�n del rat�n */ public void mouseReleased(MouseEvent e) { if(!e.isPopupTrigger()) return; if(e.getComponent() == famlist.getList()) fampopup.show((Component) e.getSource(), e.getX(), e.getY()); else mfpopup.show((Component) e.getSource(), e.getX(), e.getY()); } /** * Interfaz MouseListener - Acci�n de entrar con el rat�n en el componente */ public void mouseEntered(MouseEvent e) { } /** * Interfaz MouseListener - Acci�n de salir con el rat�n del componente */ public void mouseExited(MouseEvent e) { } /** * Interfaz ListSelectionListener */ public void valueChanged(ListSelectionEvent e) { selectMF(); } /** * Interfaz ListCellRenderer */ public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { Color blocked = dataform[0].getBackground(); int local; if(famlist.getList() == list) { local = copy.getFamilies().length; } else { local = copy.getMembershipFunctions().length; } JLabel renderer = new JLabel(value.toString()); renderer.setForeground(Color.black); if(isSelected) renderer.setBackground(XConstants.textselectedbg); else if(index >= local) renderer.setBackground(blocked); else renderer.setBackground(XConstants.textbackground); renderer.setOpaque(true); renderer.setFont(XConstants.textfont); return renderer; } /** * Interfaz WindowListener. Acci�n al abrir la ventana */ public void windowOpened(WindowEvent e) { } /** * Interfaz WindowListener. Acci�n al cerrar la ventana */ public void windowClosing(WindowEvent e) { cancel(); } /** * Interfaz WindowListener. Acci�n al terminar de cerrar la ventana */ public void windowClosed(WindowEvent e) { } /** * Interfaz WindowListener. Acci�n al minimizar la ventana */ public void windowIconified(WindowEvent e) { } /** * Interfaz WindowListener. Acci�n al maximizar la ventana */ public void windowDeiconified(WindowEvent e) { } /** * Interfaz WindowListener. Acci�n al activar la ventana */ public void windowActivated(WindowEvent e) { } /** * Interfaz WindowListener. Acci�n al desactivar la ventana */ public void windowDeactivated(WindowEvent e) { } //----------------------------------------------------------------------------// // M�TODOS PRIVADOS // //----------------------------------------------------------------------------// /** * Crea de la ventana */ private void build() { String lb[] = {"Ok","Apply","Reload","Cancel"}; XCommandForm form = new XCommandForm(lb,lb,this); form.setCommandWidth(120); form.block(); mflist = new XList("Membership Functions"); mflist.addListSelectionListener(this); mflist.setCellRenderer(this); mflist.addMouseListener(this); mflist.addKeyListener(this); famlist = new XList("M.F. Families"); famlist.getList().setVisibleRowCount(3); famlist.setCellRenderer(this); famlist.addMouseListener(this); famlist.addKeyListener(this); String datalabel[] = { "Name","Minimum","Maximum","Cardinality","Parent"}; dataform = new XTextForm[(copy.hasParent()? 5:4)]; for(int i=0; i<dataform.length; i++) { dataform[i] = new XTextForm(datalabel[i]); dataform[i].setLabelWidth(100); dataform[i].setFieldWidth(150); dataform[i].setAlignment(JLabel.CENTER); dataform[i].addFieldActionListener(this); dataform[i].setFieldActionCommand(datalabel[i]); } JPanel leftbox = new JPanel(); leftbox.setLayout(new BoxLayout(leftbox,BoxLayout.Y_AXIS)); leftbox.add(dataform[0]); if(dataform.length == 5) leftbox.add(dataform[4]); if(dataform.length == 5) dataform[4].setEditable(false); leftbox.add(Box.createVerticalStrut(5)); leftbox.add(new XLabel("Universe of discourse")); leftbox.add(Box.createVerticalStrut(5)); leftbox.add(dataform[1]); leftbox.add(dataform[2]); leftbox.add(dataform[3]); leftbox.add(Box.createVerticalStrut(5)); leftbox.add(famlist); leftbox.add(Box.createVerticalStrut(5)); leftbox.add(mflist); Dimension pref = leftbox.getPreferredSize(); Dimension maxd = leftbox.getMaximumSize(); leftbox.setMaximumSize(new Dimension(pref.width, maxd.height)); graph = new XfeditTypeGraphPanel(this.copy,450); Box hbox = new Box(BoxLayout.X_AXIS); hbox.add(Box.createHorizontalStrut(5)); hbox.add(leftbox); hbox.add(Box.createHorizontalStrut(5)); hbox.add(graph); hbox.add(Box.createHorizontalStrut(5)); Container content = getContentPane(); content.setLayout(new BoxLayout(content,BoxLayout.Y_AXIS)); content.add(new XLabel("Type Edition")); content.add(Box.createVerticalStrut(5)); content.add(hbox); content.add(form); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(this); setFont(XConstants.font); setLocationRelativeTo(xfeditor); pack(); createPopups(); } /** * Crea los men�s desplegables */ private void createPopups() { String famlabel[]= { "New MF family","Edit MF family", "Remove MF family" }; String famcommand[] = { "NewFamily", "EditFamily", "RemoveFamily" }; fampopup = new JPopupMenu(); JMenuItem famitem[] = new JMenuItem[famcommand.length]; for(int i=0; i<famcommand.length; i++) { famitem[i] = new JMenuItem(famlabel[i]); famitem[i].setActionCommand(famcommand[i]); famitem[i].addActionListener(this); famitem[i].setFont(XConstants.font); fampopup.add(famitem[i]); } String mflabel[]= { "New membership function","Edit membership function", "Remove membership function" }; String mfcommand[] = { "NewMF", "EditMF", "RemoveMF" }; mfpopup = new JPopupMenu(); JMenuItem mfitem[] = new JMenuItem[mfcommand.length]; for(int i=0; i<mfcommand.length; i++) { mfitem[i] = new JMenuItem(mflabel[i]); mfitem[i].setActionCommand(mfcommand[i]); mfitem[i].addActionListener(this); mfitem[i].setFont(XConstants.font); mfpopup.add(mfitem[i]); } } /** * Actualiza los campos de la ventana */ private void refresh() { dataform[0].setText(copy.getName()); dataform[1].setText(""+copy.getUniverse().min()); dataform[2].setText(""+copy.getUniverse().max()); dataform[3].setText(""+copy.getUniverse().card()); if(copy.hasParent()) { dataform[1].setFieldEnabled(false); dataform[1].setEditable(false); dataform[2].setFieldEnabled(false); dataform[2].setEditable(false); dataform[3].setFieldEnabled(false); dataform[3].setEditable(false); dataform[4].setText(copy.getParent().getName()); dataform[4].setFieldEnabled(false); dataform[4].setEditable(false); } setFamilyList(); setMFList(); graph.repaint(); } /** * Actualiza la lista de familias de funciones de pertenencia */ private void setFamilyList() { famlist.setListData(copy.getAllFamilies()); } /** * Actualiza la lista de etiquetas ling��sticas */ private void setMFList() { mflist.setListData(copy.getAllMembershipFunctions()); } /** * Lee y verifica el identificador del tipo */ private boolean getTypeName() { String name = dataform[0].getText(); if(!XConstants.isIdentifier(name)) { dataform[0].setText(""); XDialog.showMessage(dataform[0],"Invalid Name"); return false; } Type search = spec.searchType(name); if(search != null && search != original) { dataform[0].setText(""); XDialog.showMessage(dataform[0],"Invalid Name: Type already exists"); return false; } copy.setName(name); return true; } /** * Lee y verifica los valores del universo de discurso */ private boolean getUniverse() { if(copy.hasParent()) return true; boolean numeric = true; double min=0, max=0; int card=0; try { min = Double.parseDouble(dataform[1].getText()); } catch(NumberFormatException ex) { dataform[1].setText(""); numeric = false; } try { max = Double.parseDouble(dataform[2].getText()); } catch(NumberFormatException ex) { dataform[2].setText(""); numeric = false; } try { card = Integer.parseInt(dataform[3].getText()); } catch(NumberFormatException ex) { dataform[3].setText(""); numeric = false; } if(!numeric) { XDialog.showMessage(dataform[3],"Not a numeric value"); return false; } if(min>=max || card < 2) { XDialog.showMessage(dataform[3],"Invalid universe data"); return false; } if(!copy.testUniverse(min,max,card)) { XDialog.showMessage(dataform[3],"Universe conflicts with defined MFs"); return false; } try { copy.getUniverse().set(min,max,card); } catch( XflException ex) {} graph.repaint(); return true; } /** * Obtiene una copia a partir del tipo original */ private void getCopy() { this.copy = (Type) this.original.clone(); LinguisticLabel omf[] = this.original.getMembershipFunctions(); LinguisticLabel cmf[] = this.copy.getMembershipFunctions(); this.mapping = new XfeditTypeMapping[omf.length]; for(int i=0; i<omf.length; i++) this.mapping[i] = new XfeditTypeMapping(omf[i],cmf[i]); if(this.graph != null) this.graph.setType(copy); } /** * Cierra la ventana */ private void cancel() { original.setEditing(false); xfeditor.refresh(); setVisible(false); } /** * Actualiza la gr�fica con la funci�n seleccionada */ private void selectMF() { LinguisticLabel selected = null; try { selected = (LinguisticLabel) mflist.getSelectedValue(); } catch(Exception ex) {} graph.setExcluded( selected ); graph.setSelection( selected ); graph.repaint(); } /** * Crea una nueva funci�n de pertenencia */ private void newMF() { XfeditMFEditor editor = new XfeditMFEditor(this,null); editor.setVisible(true); } /** * Edita la funci�n de pertenencia seleccionada */ private void editMF() { LinguisticLabel selection = (LinguisticLabel) mflist.getSelectedValue(); if(selection == null) return; int local = copy.getMembershipFunctions().length; if(mflist.getSelectedIndex() >= local) return; XfeditMFEditor editor = new XfeditMFEditor(this,selection); editor.setVisible(true); } /** * Elimina la funci�n de pertenencia seleccionada */ private void removeMF() { LinguisticLabel selection = (LinguisticLabel) mflist.getSelectedValue(); if(selection == null) return; int local = copy.getMembershipFunctions().length; if(mflist.getSelectedIndex() >= local) return; LinguisticLabel origmf = null; for(int i=0; i<mapping.length; i++) if(mapping[i].copy == selection) origmf = mapping[i].orig; if(origmf != null && origmf.isLinked()) { String msg[] = new String[2]; msg[0] = "Cannot remove membership function "+selection+"."; msg[1] = "There are rulebases using this function."; XDialog.showMessage(xfeditor,msg); return; } copy.remove(selection); for(int i=0; i<mapping.length; i++) if(mapping[i].copy == selection) mapping[i].copy = null; setMFList(); } /** * Crea una nueva familia de funciones de pertenencia */ private void newFamily() { XfeditFamilyEditor editor = new XfeditFamilyEditor(this,null); editor.setVisible(true); } /** * Edita la familia de funciones de pertenencia seleccionada */ private void editFamily() { Family selection = (Family) famlist.getSelectedValue(); if(selection == null) return; int local = copy.getFamilies().length; if(famlist.getSelectedIndex() >= local) return; XfeditFamilyEditor editor = new XfeditFamilyEditor(this,selection); editor.setVisible(true); } /** * Elimina la familia de funciones de pertenencia seleccionada */ private void removeFamily() { Family selection = (Family) famlist.getSelectedValue(); if(selection == null) return; int local = copy.getFamilies().length; if(famlist.getSelectedIndex() >= local) return; if(selection.isLinked()) { String msg[] = new String[2]; msg[0] = "Cannot remove family "+selection+"."; msg[1] = "There are membership functions using it."; XDialog.showMessage(xfeditor,msg); return; } copy.removeFamily(selection); setFamilyList(); } /** * Actualiza los cambios sobre el tipo original */ private boolean apply() { if(!getTypeName()) return false; if(!getUniverse()) return false; Universe cu = copy.getUniverse(); Universe ou = original.getUniverse(); original.setName(copy.getName()); try { ou.set(cu.min(),cu.max(),cu.card()); } catch(Exception e) {} LinguisticLabel cmf[] = copy.getMembershipFunctions(); for(int i=0; i<cmf.length; i++) { if(cmf[i] instanceof ParamMemFunc) ((ParamMemFunc) cmf[i]).u = ou; } original.setMembershipFunctions(cmf); original.setFamilies(copy.getFamilies()); for(int i=0; i<mapping.length; i++) if(mapping[i].orig != null) spec.exchange(mapping[i].orig,mapping[i].copy); spec.setModified(true); getCopy(); setFamilyList(); setMFList(); return true; } /** * Acci�n a realizar al introducir datos sobre los campos de texto */ private void textAction(int index) { switch(index) { case 0: if(getTypeName()) dataform[1].requestFieldFocus(); return; case 1: dataform[2].requestFieldFocus(); return; case 2: dataform[3].requestFieldFocus(); return; case 3: if(getUniverse()) dataform[0].requestFieldFocus(); return; } } }