www.pudn.com > Caliph_v0.9.13+Emirv0.8.5-src.zip > AnnotationFrame.java


/* 
 * This file is part of Caliph & Emir. 
 * 
 * Caliph & Emir 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. 
 * 
 * Caliph & Emir 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 Caliph & Emir; if not, write to the Free Software 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 * 
 * Copyright statement: 
 * -------------------- 
 * (c) 2002-2004 by Mathias Lux (mathias@juggle.at) 
 * http://www.juggle.at 
 */ 
 
package at.lux.fotoannotation; 
 
/* 
 * Created by Mathias Lux, mathias@juggle.at 
 * User: Mathias Lux, mathias@juggle.at 
 * Date: 05.09.2002 
 * Time: 21:22:11 
 */ 
 
import at.know.center.wv_wr.imb.objectcatalog.semanticscreator.IMBeeApplicationPanel; 
import at.lux.components.ImageThumbPanel; 
import at.lux.fotoannotation.dialogs.*; 
import at.lux.fotoannotation.mpeg7.Mpeg7ImageDescription; 
import at.lux.fotoannotation.mpeg7.Mpeg7ThumbnailMediaProfile; 
import at.lux.fotoannotation.panels.*; 
import at.lux.fotoannotation.utils.TextChangesListener; 
import at.lux.splash.SplashScreen; 
import at.lux.StatusBar; 
import org.jdom.Document; 
import org.jdom.Element; 
import org.jdom.input.SAXBuilder; 
import org.jdom.output.XMLOutputter; 
import org.jdom.output.Format; 
 
import javax.imageio.ImageIO; 
import javax.swing.*; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 
import java.io.*; 
import java.text.DecimalFormat; 
import java.util.Properties; 
 
/** 
 * This Class is the main JFrame where the application is started. 
 * 
 * @author Mathias Lux, mathias@juggle.at 
 * @version 0.9 alpha 
 */ 
 
public class AnnotationFrame extends JFrame implements ActionListener, StatusBar { 
    public static final boolean DEBUG = false; 
    public static boolean DIRTY = false; 
    public static String TITLE_BAR = AnnotationToolkit.PROGRAM_NAME; 
    private AnnotationFrameProperties properties; 
    private ImageThumbPanel imagePanel; 
    private MetadataDescriptionPanel mdPanel; 
    private QualityPanel qualityPanel; 
    private TextDescriptionPanel textPanel; 
    // private AgentComboBoxModel agentsModel; 
    private File currentFile = null; 
    private FilePanel fp; 
    private JSplitPane lrSplit, tbSplit; 
    private JTabbedPane tabs; 
    private CreationPanel creationPanel; 
    private DecimalFormat df; 
    private JLabel status; 
    private IMBeeApplicationPanel beePanel; 
    private ColorLayoutPanel colorPanel; 
    private JPanel gridPanel1; 
    private JProgressBar garbageState; 
    private GarbageTracker gtracker; 
 
    public AnnotationFrame() { 
        super(TITLE_BAR); 
        try { 
            this.setIconImage(ImageIO.read(AnnotationFrame.class.getResource("data/icon.gif"))); 
        } catch (Exception e) { 
            debug("Couldn't set Icon: IOException " + e.getMessage()); 
        } 
        df = (DecimalFormat) DecimalFormat.getInstance(); 
        df.setMaximumFractionDigits(2); 
 
        addWindowListener(new WindowAdapter() { 
            public void windowClosing(WindowEvent event) { 
                super.windowClosing(event); 
                exitApplication(); 
            } 
        }); 
        // ------------------------------------------------------------------------------- 
        // Ueberpruefung ob das agent file existiert, sonst muss es angelegt werden ... 
        // Eine sicherheitskopie befindet sich im package ... 
        // ------------------------------------------------------------------------------- 
        debug("Checking if agentfile is here ..."); 
        File agentsFile = new File(AnnotationToolkit.AGENTS_FILE); 
        if (!agentsFile.exists()) { 
            try { 
                debug("Generating sample agents file"); 
                Document d = new SAXBuilder().build(AnnotationFrame.class.getResource("data/agents.mp7.xml")); 
                FileOutputStream fos = new FileOutputStream(agentsFile); 
                OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8"); 
                new XMLOutputter(Format.getPrettyFormat()).output(d, osw); 
                osw.close(); 
                fos.close(); 
                debug("Finished generating sample agents file"); 
            } catch (Exception e) { 
                debug("Error generating sample agents file " + e.toString() + ", " + e.getMessage()); 
            } 
        } else { 
            debug("agentfile found :)"); 
        } 
        debug("reading configurationfile ... "); 
        // ------------------------------------------------------------------------------- 
        // Ueberpruefung ob das base-object file existiert, sonst muss es angelegt werden. 
        // Eine sicherheitskopie befindet sich im package ... 
        // ------------------------------------------------------------------------------- 
        debug("Checking if agentfile is here ..."); 
        File baseobjectsFile = new File("base-objects.mp7.xml"); 
        if (!baseobjectsFile.exists()) { 
            try { 
                debug("Generating sample base-objects file"); 
                Document d = new SAXBuilder().build(AnnotationFrame.class.getResource("data/base-objects.mp7.xml")); 
                FileOutputStream fos = new FileOutputStream(baseobjectsFile); 
                OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8"); 
                new XMLOutputter(Format.getPrettyFormat()).output(d, osw); 
                osw.close(); 
                fos.close(); 
                debug("Finished generating sample base-objects file"); 
            } catch (Exception e) { 
                debug("Error generating sample base-objects file " + e.toString() + ", " + e.getMessage()); 
            } 
        } else { 
            debug("base-objects file found :)"); 
        } 
        debug("reading configurationfile ... "); 
        // ------------------------------------------------------------------------------- 
        // Ueberpruefung ob das property file existiert, sonst muss es angelegt werden ... 
        // Eine sicherheitskopie befindet sich im package ... 
        // ------------------------------------------------------------------------------- 
        File pFile = new File("properties.xml"); 
        if (!pFile.exists()) { 
            try { 
                debug("Generating sample property file"); 
                Document d = new SAXBuilder().build(AnnotationFrame.class.getResource("data/properties.xml")); 
                FileOutputStream fos = new FileOutputStream(pFile); 
                OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8"); 
                new XMLOutputter(Format.getPrettyFormat()).output(d, osw); 
                osw.close(); 
                fos.close(); 
                debug("Finished generating sample property file"); 
            } catch (Exception e) { 
                debug("Error generating sample property file " + e.toString() + ", " + e.getMessage()); 
            } 
        } 
        properties = new AnnotationFrameProperties(new File("properties.xml"), this); 
        debug("finished reading configurationfile"); 
        this.setJMenuBar(properties.getMenuBar()); 
        debug("finished creating menu"); 
 
        // ------------------------------------- 
        // Initialising main Objects ... 
        // ------------------------------------- 
        // TextChangeListener intialization for detecting changes of the document. 
        TextChangesListener.createInstance(this); 
        // ------------------------------------- 
        // Adding Components 
        // ------------------------------------- 
 
        beePanel = new IMBeeApplicationPanel(this); 
        colorPanel = new ColorLayoutPanel(); 
 
        lrSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 
        tbSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 
 
        mdPanel = new MetadataDescriptionPanel(new AgentComboBoxModel(this)); 
        imagePanel = new ImageThumbPanel(); 
        fp = new FilePanel(new File("."), this); 
        qualityPanel = new QualityPanel(new AgentComboBoxModel(this)); 
        textPanel = new TextDescriptionPanel(this); 
        creationPanel = new CreationPanel(new AgentComboBoxModel(this)); 
 
        JPanel qualTextPanel = new JPanel(new BorderLayout()); 
        qualTextPanel.add(qualityPanel, BorderLayout.SOUTH); 
        qualTextPanel.add(textPanel, BorderLayout.CENTER); 
        gridPanel1 = new JPanel(new GridLayout(0, 2)); 
        JPanel _leftPanel1 = new JPanel(new BorderLayout()); 
//        gridPanel2.add(textPanel); 
        _leftPanel1.add(qualTextPanel, BorderLayout.CENTER); 
        _leftPanel1.add(mdPanel, BorderLayout.SOUTH); 
        gridPanel1.add(_leftPanel1); 
        gridPanel1.add(creationPanel); 
        JPanel gridPanel3 = new JPanel(new GridLayout(0, 1)); 
        gridPanel3.add(colorPanel); 
//        gridPanel3.add(qualTextPanel); 
 
        tabs = new JTabbedPane(JTabbedPane.TOP); 
        tabs.add("Image Information", gridPanel1); 
        tabs.add("Semantics", beePanel); 
        tabs.add("Visuals", gridPanel3); 
 
        tbSplit.add(fp, JSplitPane.TOP); 
        tbSplit.add(imagePanel, JSplitPane.BOTTOM); 
 
        lrSplit.add(tbSplit, JSplitPane.LEFT); 
        lrSplit.add(tabs, JSplitPane.RIGHT); 
 
        lrSplit.setDividerLocation(properties.getLrSplit()); 
        tbSplit.setDividerLocation(properties.getTbSplit()); 
 
        status = new JLabel("Status"); 
        garbageState = new JProgressBar(JProgressBar.HORIZONTAL, 0, 100); 
        garbageState.setStringPainted(true); 
        garbageState.setPreferredSize(new Dimension(100, 18)); 
        garbageState.setToolTipText("This bar shows the memory allocated by the VM and how much of it is already in use."); 
        gtracker = new GarbageTracker(garbageState); 
 
        JPanel sgcPanel = new JPanel(new BorderLayout()); 
        sgcPanel.add(garbageState, BorderLayout.EAST); 
        sgcPanel.add(status, BorderLayout.CENTER); 
 
        this.getContentPane().add(lrSplit, BorderLayout.CENTER); 
        this.getContentPane().add(sgcPanel, BorderLayout.SOUTH); 
 
        this.setSize(properties.getFrameWidth(), properties.getFrameHeigth()); 
        this.setLocation(properties.getFrameLocationX(), properties.getFrameLocationY()); 
 
        beePanel.reArrange(); 
        //beePanel.revalidate(); 
        gtracker.start(); 
    } 
 
    /** 
     * Main method used to start Caliph 
     * 
     * @param args 
     */ 
    public static void main(String[] args) { 
/* 
        try { 
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
        } catch (Exception e) { 
            System.err.println("Could not set Look & Feel: " + e.toString()); 
        } 
*/ 
        AnnotationFrame frame = new AnnotationFrame(); 
        boolean showSplash = true; 
 
        // get config file from splashscreen class 
        File splashProps = new File(SplashScreen.LICENSE_ACCEPTED_FILENAME); 
        // look if exists 
        if (splashProps.exists()) { 
            // load props 
            try { 
                Properties licenseAcceptedProps = new Properties(); 
                licenseAcceptedProps.load(new FileInputStream(splashProps)); 
                // if property is set we do not have to show the splashscreen: 
                String tmp = licenseAcceptedProps.getProperty("license.accepted"); 
                if (tmp != null && tmp.equals("true")) { 
                    showSplash = false; 
                } 
            } catch (IOException e) { 
                System.err.println("Warn: Could not read license properties file."); 
            } 
        } 
 
        if (showSplash) { 
            // now show the splash screen if this has not been done before. 
            SplashScreen splash = new SplashScreen(frame); 
            splash.setVisible(true); 
        } 
 
        frame.setVisible(true); 
    } 
 
    /** 
     * implemented from Interface ActionListener 
     */ 
    public void actionPerformed(ActionEvent event) { 
//        gtracker.run(); 
        if (event.getActionCommand().equals("exitApplication")) { 
            exitApplication(); 
        } else if (event.getActionCommand().equals("openFile")) { 
            debug("open file operation initiated"); 
            openFile(); 
            debug("open file operation ended"); 
        } else if (event.getActionCommand().equals("showAbout")) { 
            AboutDialog adialog = new AboutDialog(this); 
            adialog.pack(); 
            Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); 
            adialog.setLocation((ss.width - adialog.getWidth()) / 2, (ss.height - adialog.getHeight()) / 2); 
            adialog.setVisible(true); 
        } else if (event.getActionCommand().equals("showHelp")) { 
            HelpDialog adialog = new HelpDialog(this); 
            // adialog.pack(); 
            Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); 
            adialog.setLocation((ss.width - adialog.getWidth()) / 2, (ss.height - adialog.getHeight()) / 2); 
            adialog.setVisible(true); 
        } else if (event.getActionCommand().equals("saveFileAs")) { 
            JOptionPane.showMessageDialog(this, "not implemented yet"); 
        } else if (event.getActionCommand().equals("gc")) { 
            debug("Mem: " 
                    + df.format(Runtime.getRuntime().freeMemory() / (1024.0 * 1024.0)) + "MB of " 
                    + df.format(Runtime.getRuntime().totalMemory() / (1024.0 * 1024.0)) + "MB free"); 
 
            debug("starting garbage collector ..."); 
            System.gc(); 
            debug("finished collecting garbage!"); 
 
            debug("Mem: " 
                    + df.format(Runtime.getRuntime().freeMemory() / (1024.0 * 1024.0)) + "MB of " 
                    + df.format(Runtime.getRuntime().totalMemory() / (1024.0 * 1024.0)) + "MB free"); 
            status.setText("Garbage collection finished: " 
                    + df.format(Runtime.getRuntime().freeMemory() / (1024.0 * 1024.0)) + "MB of " 
                    + df.format(Runtime.getRuntime().totalMemory() / (1024.0 * 1024.0)) + "MB free"); 
//            gtracker.start(); 
 
        } else if (event.getActionCommand().equals("viewXML")) { 
            TextPreviewDialog preview = new TextPreviewDialog(this, createDocument()); 
            preview.setSize(properties.getTextViewWidth(), properties.getTextViewHeight()); 
            Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); 
            preview.setLocation((ss.width - preview.getWidth()) / 2, (ss.height - preview.getHeight()) / 2); 
            preview.setVisible(true); 
            properties.setTextViewHeight(preview.getHeight()); 
            properties.setTextViewWidth(preview.getWidth()); 
        } else if (event.getActionCommand().equals("saveFile")) { 
            if (currentFile != null) { 
                saveFile(); 
            } else { 
                JOptionPane.showMessageDialog(this, "No image selected!"); 
            } 
        } else if (event.getActionCommand().equals("viewExternal")) { 
            if (currentFile != null && properties.getExternalViewer() != null) { 
                try { 
                    debug("Run: " + properties.getExternalViewer() + " \"" + currentFile.getCanonicalPath() + "\""); 
                    Runtime.getRuntime().exec(properties.getExternalViewer() + " \"" + currentFile.getCanonicalPath() + "\""); 
                } catch (IOException e) { 
                    debug("Error with external viewer - " + e.toString() + ": " + e.getMessage()); 
                } 
            } 
        } else if (event.getActionCommand().equals("setExternal")) { 
            ExternalViewerSelectDialog d = new ExternalViewerSelectDialog(this, properties.getExternalViewer()); 
            d.pack(); 
            Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); 
            d.setLocation((ss.width - d.getWidth()) / 2, (ss.height - d.getHeight()) / 2); 
            d.setVisible(true); 
 
            properties.setExternalViewer(d.getExternalViewer()); 
        } else if (event.getActionCommand().equals("autoPilot")) { 
            if (currentFile != null) { 
                startAutoPilot(); 
            } 
        } else if (event.getActionCommand().equals("delAgent")) { 
            DeleteAgentDialog d = new DeleteAgentDialog(this); 
            d.pack(); 
            Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); 
            d.setLocation((ss.width - d.getWidth()) / 2, (ss.height - d.getHeight()) / 2); 
            d.setVisible(true); 
 
        } else { 
            JOptionPane.showMessageDialog(this, "Not Implemented!"); 
        } 
    } 
 
    /** 
     * is called when applikation is exited ... 
     * saving properties and closing app. 
     * todo: save file? dialog 
     */ 
    private void exitApplication() { 
        properties.setFrameHeigth(this.getHeight()); 
        properties.setFrameWidth(this.getWidth()); 
        properties.setFrameLocationX(this.getLocation().x); 
        properties.setFrameLocationY(this.getLocation().y); 
        properties.setTbSplit(tbSplit.getDividerLocation()); 
        properties.setLrSplit(lrSplit.getDividerLocation()); 
        debug("saving configuration ..."); 
        properties.saveConfiguration(); 
        debug("finished saving configuration"); 
        debug("saving semantic objects ..."); 
        beePanel.saveCatalog(); 
        debug("semantic objects saved"); 
        if (DIRTY) { 
            if (askIfSave()) { 
                System.exit(0); 
            } 
        } else { 
            System.exit(0); 
        } 
    } 
 
    private boolean askIfSave() { 
        int returnVal = JOptionPane.showConfirmDialog(this, "Would you like to save your changes? Otherwise your changes will be lost.", "Save description?", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); 
        if (returnVal == JOptionPane.YES_OPTION) { 
            debug("Save file ..."); 
            saveFile(); 
            return true; 
        } else if (returnVal == JOptionPane.NO_OPTION) { 
            debug("Quit without saving ..."); 
            return true; 
        } else { 
            debug("no quitting, no saving :)"); 
            return false; 
        } 
    } 
 
    private void startAutoPilot() { 
        AutoPilotThread t = new AutoPilotThread(this, currentFile); 
        t.start(); 
    } 
 
    /** 
     * is called when a file is explicitely openend, meanwhile not used :) 
     */ 
    private void openFile() { 
        JFileChooser jfc = new JFileChooser(properties.getLastDir()); 
        // jfc.setCurrentDirectory(new File(properties.getLastDir())); 
        if (JFileChooser.APPROVE_OPTION == jfc.showOpenDialog(this)) { 
            debug("opening file: " + jfc.getSelectedFile().toString()); 
            properties.setLastDir(jfc.getCurrentDirectory().toString()); 
            debug("saving path: " + jfc.getCurrentDirectory().toString()); 
            try { 
                setCurrentFile(jfc.getSelectedFile()); 
            } catch (IOException e) { 
                debug("Error reading File: " + e.toString()); 
            } 
        } 
        // System.gc(); 
    } 
 
    /** 
     * Set the "dirty" trag if information has changed :) needed for 
     * bugging the user with questions like: Do you want to save the 
     * file? or Unsaved changes will be lost :) 
     * 
     * @param isDirty 
     */ 
    public static void setDirty(boolean isDirty) { 
        DIRTY = isDirty; 
    } 
 
    /** 
     * set a new Image to edit ... thread-based ... 
     */ 
    public void setCurrentFile(File f) throws IOException { 
        boolean loadIt = true; 
        if (DIRTY) { 
            loadIt = askIfSave(); 
        } 
        if (loadIt) { 
            ImageLoader t = new ImageLoader(status, this, f, imagePanel, creationPanel, textPanel, mdPanel, qualityPanel, 
                    beePanel, colorPanel); 
            t.start(); 
            currentFile = f; 
        } 
    } 
 
    /** 
     * loadCurrentFile is the not thread based method to load a file, it's used 
     * by the autopilot 
     * 
     * @param f defines the file to open 
     * @throws IOException 
     */ 
    public void loadCurrentFile(File f) throws IOException { 
        ImageLoader t = new ImageLoader(status, this, f, imagePanel, creationPanel, textPanel, mdPanel, qualityPanel, 
                beePanel, colorPanel); 
        t.run(); 
 
        currentFile = f; 
    } 
 
    public void saveFile() { 
        if (currentFile != null) { 
            try { 
                XMLOutputter op = new XMLOutputter(Format.getPrettyFormat()); 
                String imgName = currentFile.getCanonicalPath(); 
                String fname = imgName.substring(0, imgName.lastIndexOf(".")); 
                fname = fname + ".mp7.xml"; 
                File saveFile = new File(fname); 
                // check if file is arleady in existence and ask if we should overwrite: 
//                boolean write = false; 
//                if (saveFile.exists()) { 
//                    if (JOptionPane.showConfirmDialog(this, 
//                            "Overwrite existing file?", "Overwrite?", 
//                            JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { 
//                        write = true; 
//                    } 
//                } else { 
//                    write = true; 
//                } 
                if (true) { 
                    FileOutputStream fos = new FileOutputStream(saveFile); 
                    OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8"); 
                    op.output(createDocument(), osw); 
                    osw.close(); 
                    fos.close(); 
                    debug("File written to " + saveFile.toString()); 
                    status.setText("File written to " + saveFile.toString()); 
                    setDirty(false); 
                    if (getTitle().indexOf('*') > -1) 
                        setTitle(getTitle().substring(2)); 
                } 
            } catch (IOException e) { 
                debug("Exception while saving " + e.toString()); 
            } 
        } 
 
    } 
 
 
    /** 
     * This is the method where all the information is collected and put together. The result is valid 
     * MPEG-7 Description 
     */ 
    public Document createDocument() { 
        Element mediaFormat, creation, tmp, semantics; 
        tmp = creationPanel.createXML(); 
        mediaFormat = (Element) tmp.getChild("MediaFormat", tmp.getNamespace()).detach(); 
        creation = (Element) tmp.getChild("CreationInformation", tmp.getNamespace()).detach(); 
        tmp = beePanel.getSemanticsDocument().getRootElement(); 
        semantics = ((Element) tmp.getChild("Description", tmp.getNamespace()).getChild("Semantics", 
                tmp.getNamespace()).clone()); 
        semantics.setName("Semantic"); 
        File thumbFile = AnnotationToolkit.generateThumbnail(currentFile); 
        Element thumbNailProfile = null; 
        Mpeg7ThumbnailMediaProfile thumbnail = null; 
        thumbnail = new Mpeg7ThumbnailMediaProfile(thumbFile, 120, 120); 
        thumbNailProfile = thumbnail.createDocument(); 
 
        Mpeg7ImageDescription m7id = new Mpeg7ImageDescription(creation, mdPanel.createXML(), mediaFormat, 
                AnnotationToolkit.getMpeg7MediaInstance(currentFile), 
                qualityPanel.createXML(), thumbNailProfile, semantics, textPanel.createXML(), colorPanel.createXML()); 
        return m7id.createDocument(); 
    } 
 
    private void debug(String message) { 
        if (DEBUG) System.out.println("[at.lux.fotoannotation.AnnotationFrame] " + message); 
    } 
 
    public void setStatus(String message) { 
        status.setText(message); 
    } 
 
    public String getSemanticAgentsNames() { 
        String[] names = beePanel.getSemanticAgentsNames(); 
        return createStringFromArray(names); 
    } 
 
    private String createStringFromArray(String[] names) { 
        StringWriter sw = new StringWriter(names.length * 32); 
        for (int i = 0; i < names.length; i++) { 
            sw.append(names[i]); 
            if (i < names.length - 1) sw.append(", "); 
        } 
        return sw.toString(); 
    } 
 
    public String getSemanticEventsNames() { 
        String[] names = beePanel.getSemanticEventsNames(); 
        return createStringFromArray(names); 
    } 
 
    public String getSemanticTimesNames() { 
        String[] names = beePanel.getSemanticTimesNames(); 
        return createStringFromArray(names); 
    } 
 
    public String getSemanticPlacesNames() { 
        String[] names = beePanel.getSemanticPlacesNames(); 
        return createStringFromArray(names); 
    } 
}