Index: lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixTableModelND.java diff -u lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixTableModelND.java:1.1 lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixTableModelND.java:1.2 --- lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixTableModelND.java:1.1 Wed Mar 22 19:38:47 2006 +++ lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixTableModelND.java Thu Jun 1 17:38:56 2006 @@ -23,10 +23,10 @@ * Created: 21 mars 2006 19:01:27 * * @author poussin - * @version $Revision: 1.1 $ + * @version $Revision: 1.2 $ * - * Last update: $Date: 2006/03/22 19:38:47 $ - * by : $Author: bpoussin $ + * Last update: $Date: 2006/06/01 17:38:56 $ + * by : $Author: ruchaud $ */ package org.codelutin.math.matrix.gui; @@ -356,6 +356,8 @@ setForeground(fg); setFont(font); setBorder(border); + return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, + row, column); } return this; Index: lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixPanelEditor.java diff -u lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixPanelEditor.java:1.10 lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixPanelEditor.java:1.11 --- lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixPanelEditor.java:1.10 Mon May 22 12:39:07 2006 +++ lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixPanelEditor.java Thu Jun 1 17:38:56 2006 @@ -24,50 +24,41 @@ * * @author Benjamin Poussin * - * @version $Revision: 1.10 $ + * @version $Revision: 1.11 $ * - * Mise a jour: $Date: 2006/05/22 12:39:07 $ par : $Author: bpoussin $ + * Mise a jour: $Date: 2006/06/01 17:38:56 $ par : $Author: ruchaud $ */ package org.codelutin.math.matrix.gui; import java.awt.BorderLayout; -import java.awt.Component; +import java.awt.Color; import java.awt.Dimension; import java.awt.Event; -import java.awt.Toolkit; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Arrays; import java.util.Iterator; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; +import javax.swing.AbstractAction; import javax.swing.JButton; -import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; -import javax.swing.JTextArea; import javax.swing.KeyStroke; -import javax.swing.UIManager; +import javax.swing.ListSelectionModel; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.JTableHeader; import org.codelutin.math.matrix.MatrixException; import org.codelutin.math.matrix.MatrixFactory; -import org.codelutin.math.matrix.MatrixHelper; import org.codelutin.math.matrix.MatrixND; import org.codelutin.util.ListenerSet; @@ -94,6 +85,7 @@ protected JScrollPane editArea; + protected MatrixPopupMenu popupMenu; // protected JTextArea text; protected boolean linearModel = false; @@ -285,10 +277,33 @@ public JTable getTable() { if (table == null) { - table = new JTable(); - table.registerKeyboardAction(getCopyAction(), "Copy", KeyStroke - .getKeyStroke(KeyEvent.VK_C, Event.CTRL_MASK), - JComponent.WHEN_FOCUSED); + popupMenu = new MatrixPopupMenu(this); + table = new JTable(){ + public void processMouseEvent(MouseEvent event) { + if(event.isPopupTrigger()) { + popupMenu.show(event.getComponent(), + event.getX(), event.getY()); + } + super.processMouseEvent(event); + } + }; + + table.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, Event.CTRL_MASK), "copy"); + table.getActionMap().put("copy", popupMenu.getSendToClipBoardSelectionCopyAction()); + + table.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_V, Event.CTRL_MASK), "paste"); + table.getActionMap().put("paste", popupMenu.getSendToClipBoardSelectionCopyAction()); + + /*table.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK), "selectAll"); + table.getActionMap().put("selectAll", new AbstractAction(){ + public void actionPerformed(ActionEvent e) { + table.selectAll(); + }});*/ + + table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); + table.setCellSelectionEnabled(true); + } return table; } @@ -348,26 +363,6 @@ return enabled; } - protected ActionListener copyAction; - - public ActionListener getCopyAction() { - if (copyAction == null) { - copyAction = new ActionListener() { - - public void actionPerformed(ActionEvent e) { - copyPerformed(); - } - }; - } - return copyAction; - } - - private void copyPerformed() { - StringSelection contents = new StringSelection(m.toString()); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(contents, contents); - } - /* (non-Javadoc) * @see javax.swing.event.TableModelListener#tableChanged(javax.swing.event.TableModelEvent) */ @@ -382,7 +377,7 @@ l.matrixChanged(e); } } - + /** * Une petite fonction main pour le test... */ @@ -391,7 +386,7 @@ MatrixPanelEditor ed = null; try { ed = new MatrixPanelEditor(true); - ed.setLinearModel(true); + ed.setLinearModel(false); frame.getContentPane().add(ed); // MatriceND m = new MatriceNDImpl(new int[]{4,4}); @@ -405,6 +400,15 @@ List sem1 = Arrays.asList(new String[] { "toto", "titi", "tutu" }); List sem2 = Arrays.asList(new String[] { "tata", "tete", "tyty" }); List sem3 = Arrays.asList(new String[] { "riri", "fifi", "loulou" }); + + /*MatrixND m = MatrixFactory.getInstance().create(new int[]{100,100});*/ + + /*MatrixND m = MatrixFactory.getInstance().create("name", + new List[] { sem1, sem2 }, new String[]{"dim1", "dim2"}); + m.setValue(0, 0, 1); + m.setValue(0, 1, 2); + m.setValue(0, 2, 3);*/ + MatrixND m = MatrixFactory.getInstance().create("name", new List[] { sem1, sem2, sem3 }, new String[]{"dim1", "dim2", "dim3"}); Index: lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixPopupMenu.java diff -u /dev/null lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixPopupMenu.java:1.1 --- /dev/null Thu Jun 1 17:39:02 2006 +++ lutinmatrix/src/java/org/codelutin/math/matrix/gui/MatrixPopupMenu.java Thu Jun 1 17:38:56 2006 @@ -0,0 +1,522 @@ +/* *##% + * Copyright (C) 2006 + * Code Lutin, Cédric Pineau, Benjamin Poussin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *##%*/ + +/* * + * MatrixPopupMenu.java + * + * Created: 22 mars 2006 12:11:46 + * + * @author poussin + * @version $Revision: 1.1 $ + * + * Last update: $Date: 2006/06/01 17:38:56 $ + * by : $Author: ruchaud $ + */ + +package org.codelutin.math.matrix.gui; + +import static org.codelutin.i18n.I18n._; + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFileChooser; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPopupMenu; +import javax.swing.JSeparator; +import javax.swing.filechooser.FileFilter; + +import org.codelutin.math.matrix.MatrixND; +import org.codelutin.util.FileUtil; + +/** + * Ajout d'un menu contextuel sur la matrice dans l'editeur + * + * @author ruchaud + * + */ +public class MatrixPopupMenu extends JPopupMenu { + + private MatrixPanelEditor matrixEditor; + private JFileChooser fileChooser; + + private JMenu sendToClipBoard; + private JMenu sendToFile; + + private JCheckBoxMenuItem withSemantics; + + private Action sendToClipBoardAllCopyAction; + private Action sendToClipBoardAllPasteAction; + private Action sendToClipBoardSelectionCopyAction; + private Action sendToClipBoardCurrentPasteAction; + + private Action sendToFileAllCopyAction; + private Action sendToFileAllPasteAction; + private Action sendToFileSelectionCopyAction; + private Action sendToFileCurrentPasteAction; + + public MatrixPopupMenu(MatrixPanelEditor matrixEditor) { + super(); + this.matrixEditor = matrixEditor; + + sendToClipBoard = getSendToClipBoard(); + sendToFile = getSendToFile(); + + withSemantics = new JCheckBoxMenuItem(_("Exportation avec sémantiques"), true); + + add(sendToClipBoard); + add(sendToFile); + add(new JSeparator()); + add(withSemantics); + } + + /** + * @return retourne le menu d'action pour le bloc note + */ + public JMenu getSendToClipBoard() { + if (sendToClipBoard == null) { + sendToClipBoard = new JMenu(_("Envoyer vers le bloc note")); + JMenuItem sendToClipBoardAllCopy = new JMenuItem(_("Tout copier")); + JMenuItem sendToClipBoardAllPaste = new JMenuItem(_("Tout coller")); + JMenuItem sendToClipBoardSelectionCopy = new JMenuItem(_("Copier la sélection")); + JMenuItem sendToClipBoardCurrentPaste = new JMenuItem(_("Coller à la position courante")); + + sendToClipBoard.add(sendToClipBoardAllCopy); + sendToClipBoard.add(sendToClipBoardAllPaste); + sendToClipBoard.add(new JSeparator()); + sendToClipBoard.add(sendToClipBoardSelectionCopy); + sendToClipBoard.add(sendToClipBoardCurrentPaste); + + sendToClipBoardAllCopy.addActionListener(getSendToClipBoardAllCopyAction()); + sendToClipBoardAllPaste.addActionListener(getSendToClipBoardAllPasteAction()); + sendToClipBoardSelectionCopy.addActionListener(getSendToClipBoardSelectionCopyAction()); + sendToClipBoardCurrentPaste.addActionListener(getSendToClipBoardCurrentPasteAction()); + } + + return sendToClipBoard; + } + + /** + * @return retourne le menu d'action pour les fichiers CSV + */ + public JMenu getSendToFile() { + if (sendToFile == null) { + sendToFile = new JMenu(_("Envoyer vers fichier CSV")); + JMenuItem sendToFileAllCopy = new JMenuItem(_("Tout copier")); + JMenuItem sendToFileAllPaste = new JMenuItem(_("Tout coller")); + JMenuItem sendToFileSelectionCopy = new JMenuItem(_("Copier la sélection")); + JMenuItem sendToFileCurrentPaste = new JMenuItem(_("Coller à la position courante")); + + sendToFile.add(sendToFileAllCopy); + sendToFile.add(sendToFileAllPaste); + sendToFile.add(new JSeparator()); + sendToFile.add(sendToFileSelectionCopy); + sendToFile.add(sendToFileCurrentPaste); + + sendToFileAllCopy.addActionListener(getSendToFileAllCopyAction()); + sendToFileAllPaste.addActionListener(getSendToFileAllPasteAction()); + sendToFileSelectionCopy.addActionListener(getSendToFileSelectionCopyAction()); + sendToFileCurrentPaste.addActionListener(getSendToFileCurrentPasteAction()); + } + + return sendToFile; + } + + /** + * @return retourne un writer du fichier choisi dans le selecteur de fichier + * @throws IOException + */ + private Writer getFileChooserWriter() throws IOException { + int returnVal = getFileChooser().showOpenDialog(matrixEditor); + if(returnVal == JFileChooser.APPROVE_OPTION) { + File selectedFile = getFileChooser().getSelectedFile(); + return FileUtil.getWriter(selectedFile); + } + return null; + } + + /** + * @return retourne un writer pour le bloc note + */ + private Writer getClipBoardWriter() { + return new StringWriter(); + } + + /** + * @return retourne un reader du fichier choisi dans le selecteur de fichier + * @throws IOException + */ + private Reader getFileChooserReader() throws IOException { + int returnVal = getFileChooser().showOpenDialog(matrixEditor); + if(returnVal == JFileChooser.APPROVE_OPTION) { + File selectedFile = getFileChooser().getSelectedFile(); + return FileUtil.getReader(selectedFile); + } + return null; + } + + /** + * @return retourne le contenu du bloc note sous la forme d'un reader + */ + private Reader getClipBoardReader() { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + Transferable contents = clipboard.getContents(clipboard); + if (contents != null) { + try { + String data = (String) contents.getTransferData(DataFlavor.stringFlavor); + return new StringReader(data); + } catch (Exception e) { + JOptionPane.showMessageDialog(matrixEditor, + "Impossible de coller les données", "Warning", + JOptionPane.WARNING_MESSAGE); + e.printStackTrace(); + } + } + return null; + } + + /** + * Desactive le menu si la matrice ne supporte pas le mode CSV + */ + protected void firePopupMenuWillBecomeVisible() { + if(!getMatrix().isSupportedCSV()) { + sendToClipBoard.setEnabled(false); + sendToFile.setEnabled(false); + } else { + sendToClipBoard.setEnabled(true); + sendToFile.setEnabled(true); + } + super.firePopupMenuWillBecomeVisible(); + } + + /** + * @return Matrice en cours de saisie dans l'editeur + */ + private MatrixND getMatrix() { + return matrixEditor.getMatrix(); + } + + /** + * @return la sous matrice en cours de saisie dans l'editeur c'est a dire la partie selectionnee + */ + private MatrixND getSelectedMatrix() { + int beginSelectedColumn = matrixEditor.getTable().getSelectedColumn() -1; + int nbSelectedColumn = matrixEditor.getTable().getSelectedColumnCount(); + + int beginSelectedRow = matrixEditor.getTable().getSelectedRow() - 1; + int nbSelectedRow = matrixEditor.getTable().getSelectedRowCount(); + + if(getMatrix().getNbDim() == 1) { + return matrixEditor.getMatrix().getSubMatrix(0, beginSelectedColumn, nbSelectedColumn); + } else { + return matrixEditor.getMatrix().getSubMatrix(0, beginSelectedRow, nbSelectedRow) + .getSubMatrix(1, beginSelectedColumn, nbSelectedColumn); + } + } + + /** + * @return retourne les coordonnees de la première cellule selectionnee + */ + private int[] getCoordinatesFirstCellSelectedMatrix() { + int selectedColumn = matrixEditor.getTable().getSelectedColumn() -1; + int selectedRow = matrixEditor.getTable().getSelectedRow() - 1; + return new int[]{selectedRow, selectedColumn}; + } + + /** + * @return Selecteur de fichier CSV + */ + private JFileChooser getFileChooser() { + if(fileChooser == null) { + fileChooser = new JFileChooser(); + FileFilter filter = new FileFilter(){ + public boolean accept(File pathname) { + if (pathname.isDirectory()) { + return true; + } + + String extension = FileUtil.extension(pathname); + if (extension != null) { + if (extension.equals("csv")) { + return true; + } else { + return false; + } + } + + return false; + } + public String getDescription() { + return "Texte CSV (*.csv)"; + } + }; + fileChooser.setFileFilter(filter); + } + return fileChooser; + } + + /** + * @return retourne l'action du bloc note permettant la copie entere de la matrice + */ + public Action getSendToClipBoardAllCopyAction() { + if (sendToClipBoardAllCopyAction == null) { + sendToClipBoardAllCopyAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + sendToClipBoardAllCopyPerformed(); + } + }; + } + return sendToClipBoardAllCopyAction; + } + + /** + * @return retourne l'action du bloc note permettant la recopie entere + * de la matrice depuis le bloc note + */ + public Action getSendToClipBoardAllPasteAction() { + if (sendToClipBoardAllPasteAction == null) { + sendToClipBoardAllPasteAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + sendToClipBoardAllPastePerformed(); + } + }; + } + return sendToClipBoardAllPasteAction; + } + + /** + * @return retourne l'action du bloc note permettant la copie de la partie selectionnee + */ + public Action getSendToClipBoardSelectionCopyAction() { + if (sendToClipBoardSelectionCopyAction == null) { + sendToClipBoardSelectionCopyAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + sendToClipBoardSelectionCopyPerformed(); + } + }; + } + return sendToClipBoardSelectionCopyAction; + } + + /** + * @return retourne l'action du bloc note permettant la recopie de la partie selectionnee + * de la matrice depuis le bloc note + */ + public Action getSendToClipBoardCurrentPasteAction() { + if (sendToClipBoardCurrentPasteAction == null) { + sendToClipBoardCurrentPasteAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + sendToClipBoardCurrentPastePerformed(); + } + }; + } + return sendToClipBoardCurrentPasteAction; + } + + private void sendToClipBoardAllCopyPerformed() { + try { + Writer writer = getClipBoardWriter(); + getMatrix().exportCSV(writer, withSemantics.getState()); + StringSelection contents = new StringSelection(writer.toString()); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(contents, contents); + writer.close(); + matrixEditor.repaint(); + } catch (Exception e) { + JOptionPane.showMessageDialog(matrixEditor, + _("Impossible d'écrire dans le bloc note"), _("Erreur"), + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + + private void sendToClipBoardAllPastePerformed() { + try { + Reader reader = getClipBoardReader(); + getMatrix().importCSV(reader, new int[]{0,0}); + reader.close(); + matrixEditor.repaint(); + } catch (Exception e) { + JOptionPane.showMessageDialog(matrixEditor, + _("Donnée corrompu dans le bloc note"), _("Erreur"), + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + + private void sendToClipBoardSelectionCopyPerformed() { + try { + Writer writer = getClipBoardWriter(); + getSelectedMatrix().exportCSV(writer, withSemantics.getState()); + StringSelection contents = new StringSelection(writer.toString()); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(contents, contents); + writer.close(); + matrixEditor.repaint(); + } catch (Exception e) { + JOptionPane.showMessageDialog(matrixEditor, + _("Impossible d'écrire dans le bloc note"), _("Erreur"), + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + + private void sendToClipBoardCurrentPastePerformed() { + try { + Reader reader = getClipBoardReader(); + getMatrix().importCSV(reader, getCoordinatesFirstCellSelectedMatrix()); + reader.close(); + matrixEditor.repaint(); + } catch (Exception e) { + JOptionPane.showMessageDialog(matrixEditor, + _("Donnée corrompu dans le bloc note"), _("Erreur"), + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + + /** + * @return retourne l'action du fichier permettant la copie entere de la matrice + */ + public Action getSendToFileAllCopyAction() { + if (sendToFileAllCopyAction == null) { + sendToFileAllCopyAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + sendToFileAllCopyPerformed(); + } + }; + } + return sendToFileAllCopyAction; + } + + /** + * @return retourne l'action du fichier permettant la recopie entere + * de la matrice depuis le fichier + */ + public Action getSendToFileAllPasteAction() { + if (sendToFileAllPasteAction == null) { + sendToFileAllPasteAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + sendToFileAllPastePerformed(); + } + }; + } + return sendToFileAllPasteAction; + } + + /** + * @return retourne l'action du fichier permettant la copie de la partie selectionnee + */ + public Action getSendToFileSelectionCopyAction() { + if (sendToFileSelectionCopyAction == null) { + sendToFileSelectionCopyAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + sendToFileSelectionCopyPerformed(); + } + }; + } + return sendToFileSelectionCopyAction; + } + + /** + * @return retourne l'action du fichier permettant la recopie de la partie selectionnee + * de la matrice depuis le fichier + */ + public Action getSendToFileCurrentPasteAction() { + if (sendToFileCurrentPasteAction == null) { + sendToFileCurrentPasteAction = new AbstractAction() { + public void actionPerformed(ActionEvent e) { + sendToFileCurrentPastePerformed(); + } + }; + } + return sendToFileCurrentPasteAction; + } + + private void sendToFileAllCopyPerformed() { + try { + Writer writer = getFileChooserWriter(); + getMatrix().exportCSV(writer, withSemantics.getState()); + writer.close(); + matrixEditor.repaint(); + } catch (Exception e) { + JOptionPane.showMessageDialog(matrixEditor, + _("Impossible d'écrire dans le fichier"), _("Erreur"), + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + + private void sendToFileAllPastePerformed() { + try { + Reader reader = getFileChooserReader(); + getMatrix().importCSV(reader, new int[]{0,0}); + reader.close(); + matrixEditor.repaint(); + } catch (Exception e) { + JOptionPane.showMessageDialog(matrixEditor, + _("Impossible de lire le fichier"), _("Erreur"), + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + + private void sendToFileSelectionCopyPerformed() { + try { + Writer writer = getFileChooserWriter(); + getSelectedMatrix().exportCSV(writer, withSemantics.getState()); + writer.close(); + matrixEditor.repaint(); + } catch (Exception e) { + JOptionPane.showMessageDialog(matrixEditor, + _("Impossible d'écrire dans le fichier"), _("Erreur"), + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + + private void sendToFileCurrentPastePerformed() { + try { + Reader reader = getFileChooserReader(); + getMatrix().importCSV(reader, getCoordinatesFirstCellSelectedMatrix()); + reader.close(); + matrixEditor.repaint(); + } catch (Exception e) { + JOptionPane.showMessageDialog(matrixEditor, + _("Impossible de lire le fichier"), _("Erreur"), + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } +}