All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.datacleaner.panels.SchemaTreePanel Maven / Gradle / Ivy

/**
 * DataCleaner (community edition)
 * Copyright (C) 2014 Free Software Foundation, Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * 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 Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.datacleaner.panels;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.inject.Inject;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.SwingWorker;
import javax.swing.event.DocumentEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;

import org.datacleaner.connection.Datastore;
import org.datacleaner.guice.InjectorBuilder;
import org.datacleaner.util.DCDocumentListener;
import org.datacleaner.util.WidgetUtils;
import org.datacleaner.widgets.LoadingIcon;
import org.datacleaner.widgets.tree.SchemaTree;
import org.jdesktop.swingx.JXTextField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Strings;
import com.google.inject.Injector;

/**
 * Panel that wraps the {@link SchemaTree} as well as actions around it for
 * searching/filtering etc.
 */
public class SchemaTreePanel extends DCPanel {

    private static final long serialVersionUID = 1L;

    private static final Logger logger = LoggerFactory.getLogger(SchemaTreePanel.class);

    private static final String DEFAULT_SEARCH_FIELD_TEXT = "Search component library...";

    private final InjectorBuilder _injectorBuilder;
    private final JXTextField _searchTextField;
    private final JComponent _resetSearchButton;
    private JComponent _updatePanel;
    private SchemaTree _schemaTree;

    @Inject
    protected SchemaTreePanel(final InjectorBuilder injectorBuilder) {
        super(WidgetUtils.COLOR_DEFAULT_BACKGROUND);
        _injectorBuilder = injectorBuilder;
        _searchTextField = createSearchTextField();
        _resetSearchButton = createResetSearchButton();

        setLayout(new BorderLayout());
        setBorder(WidgetUtils.BORDER_EMPTY);
        setDatastore(null, false);

        setFocusable(true);
    }

    /**
     * Method invoked when this panel is not longer shown to the user (typically
     * because there is no longer any open datastore / job).
     *
     * Note: This method is here because the {@link #removeNotify()} method is
     * not invoked by the layout manager of the parent window.
     */
    public void onPanelHiding() {
        resetSearch();
        // remove children to notify them
        removeAll();
        updateParentPanel();
    }

    public void setDatastore(final Datastore datastore, final boolean expandTree) {
        removeAll();
        if (datastore == null) {
            add(new DCPanel().setPreferredSize(150, 150), BorderLayout.CENTER);
            return;
        }

        add(new LoadingIcon().setPreferredSize(150, 150), BorderLayout.CENTER);

        // load the schema tree in the background because it will retrieve
        // metadata about the datastore (might take several seconds)
        new SwingWorker() {
            @Override
            protected SchemaTree doInBackground() throws Exception {
                final Injector injector = _injectorBuilder.with(Datastore.class, datastore).createInjector();
                return injector.getInstance(SchemaTree.class);
            }

            protected void done() {
                try {
                    _schemaTree = get();
                    final JScrollPane schemaTreeScroll = WidgetUtils.scrolleable(_schemaTree);
                    schemaTreeScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
                    _schemaTree.addComponentListener(new ComponentAdapter() {
                        @Override
                        public void componentResized(final ComponentEvent e) {
                            updateParentPanel();
                        }
                    });
                    _schemaTree.setFocusable(true);
                    _schemaTree.addKeyListener(new KeyAdapter() {
                        @Override
                        public void keyPressed(final KeyEvent e) {
                            if (_searchTextField.isFocusOwner()) {
                                // let the normal search text work as it should
                                return;
                            }

                            final char keyChar = e.getKeyChar();
                            switch (keyChar) {
                            case KeyEvent.VK_ESCAPE:
                            case KeyEvent.VK_DELETE:
                                _searchTextField.setText("");
                                break;
                            case KeyEvent.VK_BACK_SPACE:
                                try {
                                    final Document document = _searchTextField.getDocument();
                                    final int index = document.getLength() - 1;
                                    if (index >= 0) {
                                        document.remove(index, 1);
                                    }
                                } catch (final BadLocationException ex) {
                                    logger.debug("Document.remove() failed", ex);
                                }
                                break;
                            default:
                                if (!e.isActionKey() && Character.isLetter(keyChar)) {
                                    try {
                                        final Document document = _searchTextField.getDocument();
                                        document.insertString(document.getLength(), "" + keyChar,
                                                SimpleAttributeSet.EMPTY);
                                    } catch (final BadLocationException ex) {
                                        logger.debug("Document.insertString({}) failed", keyChar, ex);
                                    }
                                }
                            }
                        }
                    });
                    removeAll();
                    add(schemaTreeScroll, BorderLayout.CENTER);

                    final DCPanel searchComponent = new DCPanel(WidgetUtils.BG_COLOR_BRIGHTEST);
                    searchComponent.setLayout(new BorderLayout());
                    searchComponent.add(_searchTextField, BorderLayout.CENTER);
                    searchComponent.add(_resetSearchButton, BorderLayout.EAST);

                    add(searchComponent, BorderLayout.SOUTH);
                    _schemaTree.expandStandardPaths();
                    if (expandTree) {
                        _schemaTree.expandSelectedData();
                    }
                    updateParentPanel();
                } catch (final Exception e) {
                    throw new RuntimeException(e);
                }
            }

        }.execute();
    }

    private JComponent createResetSearchButton() {
        final JLabel resetSearchFieldIcon = new JLabel("X");
        resetSearchFieldIcon.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        resetSearchFieldIcon.setBorder(WidgetUtils.BORDER_EMPTY);
        resetSearchFieldIcon.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(final MouseEvent e) {
                resetSearch();
            }
        });
        return resetSearchFieldIcon;
    }

    public void resetSearch() {
        final String currentText = _searchTextField.getText();
        if (Strings.isNullOrEmpty(currentText)) {
            // do nothing
            return;
        }
        _searchTextField.setText("");
        _schemaTree.filter("");
    }

    protected JXTextField createSearchTextField() {
        final JXTextField searchTextField = new JXTextField(DEFAULT_SEARCH_FIELD_TEXT);
        searchTextField.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(final FocusEvent e) {
                final int length = searchTextField.getText().length();
                searchTextField.select(length, length);
            }
        });
        searchTextField.getDocument().addDocumentListener(new DCDocumentListener() {
            @Override
            protected void onChange(final DocumentEvent event) {
                _schemaTree.filter(searchTextField.getText());
            }
        });
        searchTextField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(final KeyEvent e) {
                if (e.getKeyChar() == KeyEvent.VK_ESCAPE) {
                    searchTextField.setText("");
                }
            }
        });
        searchTextField.setBorder(WidgetUtils.BORDER_EMPTY);
        return searchTextField;
    }

    private void updateParentPanel() {
        if (_updatePanel != null) {
            _updatePanel.updateUI();
        }
    }

    public void setUpdatePanel(final JComponent updatePanel) {
        _updatePanel = updatePanel;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy