net.sf.xmm.moviemanager.gui.DialogIMDB.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.xmm.moviemanager.gui.DialogIMDB.java

Source

/**
 * @(#)DialogIMDB.java
 *
 * Copyright (2003) Mediterranean
 * 
 * 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, or 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, Boston, MA 02111.
 * 
 * Contact: mediterranean@users.sourceforge.net
 **/

package net.sf.xmm.moviemanager.gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.UnknownHostException;
import java.util.ArrayList;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JToolTip;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;

import net.sf.xmm.moviemanager.MovieManager;
import net.sf.xmm.moviemanager.http.HttpUtil.HTTPResult;
import net.sf.xmm.moviemanager.imdblib.IMDb;
import net.sf.xmm.moviemanager.imdblib.IMDbLib;
import net.sf.xmm.moviemanager.models.ModelEntry;
import net.sf.xmm.moviemanager.models.ModelMovieInfo;
import net.sf.xmm.moviemanager.models.imdb.ModelIMDbEntry;
import net.sf.xmm.moviemanager.models.imdb.ModelIMDbSearchHit;
import net.sf.xmm.moviemanager.swing.extentions.JMultiLineToolTip;
import net.sf.xmm.moviemanager.swing.util.KeyboardShortcutManager;
import net.sf.xmm.moviemanager.swing.util.SwingWorker;
import net.sf.xmm.moviemanager.util.GUIUtil;
import net.sf.xmm.moviemanager.util.Localizer;
import net.sf.xmm.moviemanager.util.tools.BrowserOpener;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.log4j.Logger;

public class DialogIMDB extends JDialog {

    private static final long serialVersionUID = -1416622463608254610L;

    static Logger log = Logger.getLogger(DialogIMDB.class);

    private JTextField searchStringField;

    private JButton buttonSelect;
    private JButton buttonCancel;
    private JButton buttonSearch;

    private JPanel panelMoviesList;

    JPanel subclassButtons;

    private JList listMovies;

    ModelEntry modelEntry = null;
    IMDb imdb = null;

    private boolean canceled = false;

    KeyboardShortcutManager shortcutManager = new KeyboardShortcutManager(this);

    public DialogIMDB(JDialog parent, ModelEntry modelEntry, String alternateTitle, boolean executeSearch) {
        super(parent);
        setup(modelEntry, alternateTitle, executeSearch);
    }

    public DialogIMDB(ModelEntry modelEntry, String alternateTitle, boolean executeSearch) {
        super(MovieManager.getDialog());
        setup(modelEntry, alternateTitle, executeSearch);
    }

    void setup(ModelEntry modelEntry, String alternateTitle, boolean executeSearch) {
        this.modelEntry = modelEntry;

        if (alternateTitle == null)
            setTitle(Localizer.get("DialogIMDB.title")); //$NON-NLS-1$
        else
            setTitle(alternateTitle);

        createListDialog();

        setHotkeyModifiers();

        searchStringField.setText(modelEntry.getTitle());

        callSearch();
    }

    JPanel createMoviehitsList() {
        /* Movies List panel...*/
        JPanel panelMoviesList = new JPanel();
        panelMoviesList.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
                        Localizer.get("DialogIMDB.panel-movie-list.title")), //$NON-NLS-1$
                BorderFactory.createEmptyBorder(5, 5, 5, 5)));

        listMovies = new JList() {

            public String getToolTipText(MouseEvent e) {

                if (getCellBounds(0, 0) == null)
                    return null;

                String retVal = null;

                int row = (int) e.getPoint().getY() / (int) getCellBounds(0, 0).getHeight();

                if (row >= 0 && row < getModel().getSize()
                        && getMoviesList().getModel().getElementAt(row) instanceof ModelIMDbSearchHit) {
                    retVal = ((ModelIMDbSearchHit) getMoviesList().getModel().getElementAt(row)).getAka();

                    if (retVal != null && retVal.trim().equals("")) //$NON-NLS-1$
                        retVal = null;
                }

                return retVal;
            }

            public JToolTip createToolTip() {
                JMultiLineToolTip tooltip = new JMultiLineToolTip();
                tooltip.setComponent(this);
                return tooltip;
            }
        };

        // Unfortunately setting tooltip timeout affects ALL tooltips
        ToolTipManager ttm = ToolTipManager.sharedInstance();
        ttm.registerComponent(listMovies);
        ttm.setInitialDelay(0);
        ttm.setReshowDelay(0);

        listMovies.setFixedCellHeight(18);

        listMovies.setFont(new Font(listMovies.getFont().getName(), Font.PLAIN, listMovies.getFont().getSize()));
        listMovies.setLayoutOrientation(JList.VERTICAL);
        listMovies.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listMovies.setCellRenderer(new MovieHitListCellRenderer());

        listMovies.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent event) {

                // Open we page
                if (SwingUtilities.isRightMouseButton(event)) {

                    int index = listMovies.locationToIndex(event.getPoint());

                    if (index >= 0) {
                        ModelIMDbSearchHit hit = (ModelIMDbSearchHit) listMovies.getModel().getElementAt(index);

                        if (hit.getUrlID() != null && !hit.getUrlID().equals("")) {
                            BrowserOpener opener = new BrowserOpener(hit.getCompleteUrl());
                            opener.executeOpenBrowser(MovieManager.getConfig().getSystemWebBrowser(),
                                    MovieManager.getConfig().getBrowserPath());
                        }
                    }
                } else if (SwingUtilities.isLeftMouseButton(event) && event.getClickCount() >= 2) {
                    buttonSelect.doClick();
                }
            }
        });

        KeyStroke enterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true);
        ActionListener listKeyBoardActionListener = new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                log.debug("ActionPerformed: " + "Movielist - ENTER pressed."); //$NON-NLS-1$
                buttonSelect.doClick();
            }
        };
        listMovies.registerKeyboardAction(listKeyBoardActionListener, enterKeyStroke, JComponent.WHEN_FOCUSED);

        JScrollPane scrollPaneMovies = new JScrollPane(listMovies);
        scrollPaneMovies.setAutoscrolls(true);
        //scrollPaneMovies.registerKeyboardAction(listKeyBoardActionListener,enterKeyStroke, JComponent.WHEN_FOCUSED);

        panelMoviesList.setLayout(new BorderLayout());
        panelMoviesList.add(scrollPaneMovies, BorderLayout.CENTER);

        return panelMoviesList;
    }

    private void createListDialog() {
        /* Dialog properties...*/

        setModal(true);
        setResizable(true);

        panelMoviesList = createMoviehitsList();
        JPanel searchPanel = createSearchStringPanel();
        JPanel panelButtons = createButtonsPanel();

        JPanel panelSearchAndButtons = new JPanel();
        panelSearchAndButtons.setLayout(new BorderLayout());
        panelSearchAndButtons.add(searchPanel, BorderLayout.NORTH);
        panelSearchAndButtons.add(panelButtons, BorderLayout.SOUTH);

        subclassButtons = new JPanel();

        JPanel sharedPanel = new JPanel();
        sharedPanel.setLayout(new BorderLayout());
        sharedPanel.add(panelSearchAndButtons, BorderLayout.NORTH);
        sharedPanel.add(subclassButtons, BorderLayout.SOUTH);

        /* To add outside border... */
        JPanel all = new JPanel();
        all.setLayout(new BorderLayout());
        all.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5), null));
        all.add(panelMoviesList, BorderLayout.CENTER);
        all.add(sharedPanel, BorderLayout.SOUTH);

        getContentPane().add(all, BorderLayout.CENTER);
        //getContentPane().add(sharedPanel,BorderLayout.SOUTH);

        getMoviesList().ensureIndexIsVisible(0);

        setPreferredSize(new Dimension(500, 440));
        setMinimumSize(new Dimension(500, 440));

        pack();

        setLocation(
                (int) MovieManager.getIt().getLocation().getX()
                        + (MovieManager.getIt().getWidth() - getWidth()) / 2,
                (int) MovieManager.getIt().getLocation().getY()
                        + (MovieManager.getIt().getHeight() - getHeight()) / 2);

    }

    private JPanel createButtonsPanel() {

        JPanel panelButtons = new JPanel();
        panelButtons
                .setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5), null));
        panelButtons.setLayout(new BorderLayout());

        /* regular Buttons panel...*/
        JPanel panelRegularButtons = new JPanel();
        panelRegularButtons.setBorder(BorderFactory.createEmptyBorder(0, 0, 4, 0));
        panelRegularButtons.setLayout(new FlowLayout());

        buttonSelect = new JButton(Localizer.get("DialogIMDB.button.select.text")); //$NON-NLS-1$
        buttonSelect.setToolTipText(Localizer.get("DialogIMDB.button.select.tooltip")); //$NON-NLS-1$
        buttonSelect.setActionCommand("GetIMDBInfo - Select"); //$NON-NLS-1$
        buttonSelect.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                log.debug("ActionPerformed: " + event.getActionCommand()); //$NON-NLS-1$

                if (!getMoviesList().isSelectionEmpty())
                    executeCommandSelect();
            }
        });

        panelRegularButtons.add(buttonSelect);

        // Search button
        buttonSearch = new JButton(Localizer.get("DialogIMDbMultiAdd.button.search.text")); //$NON-NLS-1$
        buttonSearch.setToolTipText(Localizer.get("DialogIMDbMultiAdd.button.search.tooltip")); //$NON-NLS-1$
        buttonSearch.setActionCommand("GetIMDBInfo - Search again"); //$NON-NLS-1$
        buttonSearch.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                log.debug("ActionPerformed: " + event.getActionCommand()); //$NON-NLS-1$
                executeSearch();
            }
        });

        panelRegularButtons.add(buttonSearch);

        // cancel button
        buttonCancel = new JButton(Localizer.get("DialogIMDB.button.cancel.text.cancel")); //$NON-NLS-1$
        buttonCancel.setToolTipText(Localizer.get("DialogIMDB.button.cancel.tooltip.cancel")); //$NON-NLS-1$

        buttonCancel.setActionCommand("GetIMDBInfo - Cancel"); //$NON-NLS-1$

        buttonCancel.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                log.debug("ActionPerformed: " + event.getActionCommand()); //$NON-NLS-1$
                canceled = true;
                dispose();
            }
        });

        panelRegularButtons.add(buttonCancel);
        panelButtons.add(panelRegularButtons, BorderLayout.SOUTH);

        return panelButtons;
    }

    /**
     * Creates a panel containing a text field used to search
     * @return
     */
    private JPanel createSearchStringPanel() {

        JPanel searchStringPanel = new JPanel();
        searchStringPanel.setLayout(new BorderLayout());
        searchStringPanel.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
                        Localizer.get("DialogIMDB.panel-search-string.title")), //$NON-NLS-1$
                BorderFactory.createEmptyBorder(4, 4, 4, 4)));

        searchStringField = new JTextField(27);
        searchStringField.setActionCommand("Search String:"); //$NON-NLS-1$
        searchStringField.setCaretPosition(0);
        searchStringField.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    executeSearch();
                }
            }
        });

        searchStringPanel.add(searchStringField, BorderLayout.NORTH);

        return searchStringPanel;
    }

    /**
     * This method can be overridden by subclass to avoid executeSearch 
     * being called by the constructor
     */
    void callSearch() {
        executeSearch();
    }

    void executeSearch() {
        SwingWorker worker = new SwingWorker() {
            public Object construct() {
                performSearch();
                return null;
            }
        };
        worker.start();
    }

    ArrayList<ModelIMDbSearchHit> performSearch() {

        DefaultListModel model = new DefaultListModel();
        model.addElement(
                new ModelIMDbSearchHit(Localizer.get("DialogIMDB.list-element.messsage.search-in-progress"))); //$NON-NLS-1$
        listMovies.setModel(model);

        ArrayList<ModelIMDbSearchHit> hits = null;

        try {
            hits = IMDbLib.newIMDb(MovieManager.getConfig().getHttpSettings())
                    .getSimpleMatches(searchStringField.getText());
            handleSearchResults(hits);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            executeErrorMessage(e);
            dispose();
        }
        return hits;
    }

    void handleSearchResults(ArrayList<ModelIMDbSearchHit> hits) {

        final DefaultListModel list = new DefaultListModel();

        boolean noHits = false;

        // Error
        if (hits == null) {
            HTTPResult res = imdb.getLastHTTPResult();

            if (res.getStatusCode() == HttpStatus.SC_REQUEST_TIMEOUT) {
                list.addElement(new ModelIMDbSearchHit("Connection timed out...")); //$NON-NLS-1$
                noHits = true;
            }
        } else if (hits.size() == 0) {
            list.addElement(
                    new ModelIMDbSearchHit(Localizer.get("DialogIMDB.list-element.messsage.no-hits-found"))); //$NON-NLS-1$
            noHits = true;
        } else {
            for (ModelIMDbSearchHit hit : hits)
                list.addElement(hit);
        }

        final boolean setButtonChooseEnabled = !noHits;

        // make changes on EDT
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                setListModel(list);
                listMovies.setSelectedIndex(0);
                getButtonSelect().setEnabled(setButtonChooseEnabled);
            }
        });
    }

    /**
     * Takes the current selected element, retrieves the IMDb info and disposes.
     **/
    public void executeCommandSelect() {

        int index = getMoviesList().getSelectedIndex();
        DefaultListModel listModel = (DefaultListModel) getMoviesList().getModel();

        if (index == -1 || index > listModel.size())
            return;

        ModelIMDbSearchHit model = ((ModelIMDbSearchHit) listModel.getElementAt(index));

        if (model.getUrlID() == null)
            return;

        getIMDbInfo(modelEntry, model.getUrlID());

        ModelMovieInfo.executeTitleModification(modelEntry);

        dispose();
    }

    public void setListModel(DefaultListModel list) {
        listMovies.setModel(list);
        listMovies.requestFocusInWindow();
    }

    public boolean getCanceled() {
        return canceled;
    }

    protected void setCanceled(boolean cancel) {
        canceled = cancel;
    }

    public DialogIMDB(ModelEntry modelEntry, String alternateTitle) {
        this(modelEntry, alternateTitle, true);
    }

    /**
     * Returns the JList listMovies.
     **/
    protected JList getMoviesList() {
        return listMovies;
    }

    protected JPanel getPanelMoviesList() {
        return panelMoviesList;
    }

    public JTextField getSearchField() {
        return searchStringField;
    }

    /**
     * Returns the JButton select.
     **/
    protected JButton getButtonSelect() {
        return buttonSelect;
    }

    JButton getButtonSearch() {
        return buttonSearch;
    }

    JButton getButtonCancel() {
        return buttonCancel;
    }

    /*ALerts the user of different error messages from proxy servers*/
    void executeErrorMessage(Exception e) {

        String message = e.getMessage();

        if (e instanceof UnknownHostException) {
            DialogAlert alert = new DialogAlert(this, "Unkown host", "Failed to connect to " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
            GUIUtil.showAndWait(alert, true);
        }

        if (message == null)
            return;

        if (message.startsWith("Server returned HTTP response code: 407")) { //$NON-NLS-1$
            DialogAlert alert = new DialogAlert(this,
                    Localizer.get("DialogIMDB.alert.title.authentication-required"), //$NON-NLS-1$
                    Localizer.get("DialogIMDB.alert.message.proxy-authentication-required")); //$NON-NLS-1$
            GUIUtil.showAndWait(alert, true);
        }

        if (message.startsWith("Connection timed out")) { //$NON-NLS-1$
            DialogAlert alert = new DialogAlert(this, Localizer.get("DialogIMDB.alert.title.connection-timed-out"), //$NON-NLS-1$
                    Localizer.get("DialogIMDB.alert.message.connection-timed-out")); //$NON-NLS-1$
            GUIUtil.showAndWait(alert, true);
        }

        if (message.startsWith("Connection reset")) { //$NON-NLS-1$
            DialogAlert alert = new DialogAlert(this, Localizer.get("DialogIMDB.alert.title.connection-reset"), //$NON-NLS-1$
                    Localizer.get("DialogIMDB.alert.message.connection-reset")); //$NON-NLS-1$
            GUIUtil.showAndWait(alert, true);
        }

        if (message.startsWith("Server redirected too many  times")) { //$NON-NLS-1$
            DialogAlert alert = new DialogAlert(this, Localizer.get("DialogIMDB.alert.title.access-denied"), //$NON-NLS-1$
                    Localizer.get("DialogIMDB.alert.message.username-of-password-invalid")); //$NON-NLS-1$
            GUIUtil.showAndWait(alert, true);
        }

        if (message.startsWith("The host did not accept the connection within timeout of")) { //$NON-NLS-1$
            DialogAlert alert = new DialogAlert(this, Localizer.get("DialogIMDB.alert.title.connection-timed-out"), //$NON-NLS-1$
                    message);
            GUIUtil.showAndWait(alert, true);
        }

    }

    public static boolean getIMDbInfo(ModelEntry modelEntry, String key) {
        IMDb imdb;

        try {
            //net.sf.xmm.moviemanager.http.IMDB_if i = SysUtil.getIMDBInstance();

            //imdb = i.getIMDB(key, MovieManager.getConfig().getHttpSettings());

            //net.sf.xmm.moviemanager.http.IMDB_if i = SysUtil.getIMDBInstance();

            imdb = IMDbLib.newIMDb(key, MovieManager.getConfig().getHttpSettings());
        } catch (Exception e) {
            log.error(e.getMessage(), e); //$NON-NLS-1$
            return false;
        }

        ModelIMDbEntry dataModel = imdb.getLastDataModel();

        if (key.equals(dataModel.getUrlID())) {

            modelEntry.setTitle(dataModel.getTitle());
            modelEntry.setDate(dataModel.getDate());
            modelEntry.setColour(dataModel.getColour());
            modelEntry.setDirectedBy(dataModel.getDirectedBy());
            modelEntry.setWrittenBy(dataModel.getWrittenBy());
            modelEntry.setGenre(dataModel.getGenre());
            modelEntry.setRating(dataModel.getRating());
            modelEntry.setPersonalRating(dataModel.getPersonalRating());
            modelEntry.setCountry(dataModel.getCountry());
            modelEntry.setLanguage(dataModel.getLanguage());
            modelEntry.setPlot(dataModel.getPlot());
            modelEntry.setCast(dataModel.getCast());

            modelEntry.setWebRuntime(dataModel.getWebRuntime());
            modelEntry.setWebSoundMix(dataModel.getWebSoundMix());
            modelEntry.setAwards(dataModel.getAwards());
            modelEntry.setMpaa(dataModel.getMpaa());
            modelEntry.setAka(dataModel.getAka());
            modelEntry.setCertification(dataModel.getCertification());

            modelEntry.setUrlKey(dataModel.getUrlID());

            /* The cover... */
            byte[] coverData = dataModel.getCoverData();

            if (dataModel.hasCover()) {

                modelEntry.setCover(dataModel.getCoverName());
                modelEntry.setCoverData(coverData);
            } else {
                modelEntry.setCover(null);
                modelEntry.setCoverData(null);
            }

            // Big cover available
            if (imdb.retrieveBiggerCover(dataModel)) {
                modelEntry.setCoverData(dataModel.getBigCoverData());
            }
        }
        return true;
    }

    public class MovieHitListCellRenderer extends DefaultListCellRenderer {

        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
                boolean hasFocus) {
            super.getListCellRendererComponent(list, value, index, isSelected, hasFocus);

            if (value instanceof ModelIMDbSearchHit) {

                //String category = ((ModelIMDbSearchHit) value).getHitCategory();

                //"Popular Titles", "Titles (Exact Matches)", "Titles (Partial Matches)", "Titles (Approx Matches)

                /*
                if (category == null)
                   setBackground(null);                          
                else if (category.equals("Popular Titles"))
                   setBackground(new Color(162, 179, 243));
                else if (category.equals("Titles (Exact Matches)"))
                   setBackground(new Color(240, 119, 119));
                else if (category.equals("Titles (Partial Matches)"))
                   setBackground(new Color(236, 240, 119));
                else if (category.equals("Titles (Approx Matches)"))
                   setBackground(new Color(119, 240, 124));
                */

            }
            return this;
        }
    }

    private void setHotkeyModifiers() {

        try {

            GUIUtil.enableDisposeOnEscapeKey(shortcutManager, "Close window (and discard)", new AbstractAction() {
                public void actionPerformed(ActionEvent arg0) {
                    setCanceled(true);
                }
            });

            // ALT+K to show the shortcut map
            shortcutManager.registerShowKeysKey();

            // ALT+S for Select
            shortcutManager.registerKeyboardShortcut(
                    KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyboardShortcutManager.getToolbarShortcutMask()),
                    "Select/Save selected title", new AbstractAction() {
                        public void actionPerformed(ActionEvent ae) {
                            buttonSelect.doClick();
                        }
                    }, buttonSelect);

            // ALT+C for Cancel
            shortcutManager.registerKeyboardShortcut(
                    KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyboardShortcutManager.getToolbarShortcutMask()),
                    "Cancel (Discard) this movie", new AbstractAction() {
                        public void actionPerformed(ActionEvent ae) {
                            buttonCancel.doClick();
                        }
                    }, buttonCancel);

            // ALT+F for search field focus
            shortcutManager.registerKeyboardShortcut(
                    KeyStroke.getKeyStroke(KeyEvent.VK_F, KeyboardShortcutManager.getToolbarShortcutMask()),
                    "Give search field focus or perform search if already focused.", new AbstractAction() {
                        public void actionPerformed(ActionEvent ae) {

                            if (!searchStringField.hasFocus()) {
                                searchStringField.requestFocusInWindow();
                            } else {
                                buttonSearch.doClick();
                            }
                        }
                    }, buttonSearch);

            shortcutManager.setKeysToolTipComponent(panelMoviesList);
        } catch (Exception e) {
            log.warn("Exception:" + e.getMessage(), e);
        }
    }
}