/** * Copyright 2013 Alexander Erhard * <p> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.aerhard.oxygen.plugin.dbtagger; import com.aerhard.oxygen.plugin.dbtagger.ui.Table; import com.aerhard.oxygen.plugin.dbtagger.util.HttpUtil; import com.aerhard.oxygen.plugin.dbtagger.util.JsonUtil; import com.jidesoft.swing.InfiniteProgressPanel; import ro.sync.annotations.api.API; import ro.sync.annotations.api.APIType; import ro.sync.annotations.api.SourceType; import ro.sync.ecss.extensions.commons.ui.OKCancelDialog; import ro.sync.exml.workspace.api.Workspace; import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import java.awt.*; import java.awt.event.*; import java.util.ResourceBundle; /** * The search dialog component. */ @API(type = APIType.INTERNAL, src = SourceType.PUBLIC) public class SearchDialog extends OKCancelDialog { private static final long serialVersionUID = 1L; /** * The preferred width of the config window. */ private static final int PREFERRED_TABLE_WIDTH = 800; /** * The preferred heigth of the config window. */ private static final int PREFERRED_TABLE_HEIGHT = 400; /** * The default border width of the content items */ private static final int BORDER_W = 5; /** * The search action key "search" */ private static final String SEARCH = "search"; /** * The search field component. */ private JTextField searchField; /** * The main search results table component. */ private Table mainTable; /** * The search results table component for sub item results. */ private Table subTable = null; /** * The model of the search results table. */ private DefaultTableModel tableModel = null; /** * The json utility. */ private JsonUtil jsonUtil; /** * The http utility. */ private HttpUtil httpUtil; /** * The localization resource bundle. */ private ResourceBundle i18n; /** * The loading mask. */ private InfiniteProgressPanel loadingMask; /** * The fixed part of the main table server request URL. */ private String mainUrl; /** * The server request user name. */ private String user; /** * The server request password. */ private String password; /** * The submittedItem */ private String[] submittedItem = null; /** * Instantiates a new search dialog. * * @param workspace oXygen's workspace object. * @param title The dialog title * @param user The database user * @param password The database password * @param mainUrl The URL for main item queries. * @param subUrl The URL for sub item queries. * @param searchFieldText The text to put in the search field. */ public SearchDialog(Workspace workspace, String title, String user, String password, String mainUrl, final String subUrl, String searchFieldText) { super((Frame) workspace.getParentFrame(), title, true); this.mainUrl = mainUrl; this.user = user; this.password = password; jsonUtil = new JsonUtil(workspace); httpUtil = new HttpUtil(); i18n = ResourceBundle.getBundle("Tagger"); loadingMask = new InfiniteProgressPanel(); setGlassPane(loadingMask); getContentPane().setLayout(new BorderLayout(0, 8)); getContentPane().add(createSearchFieldPane(searchFieldText), BorderLayout.NORTH); mainTable = new Table(); mainTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); initTableListeners(mainTable); if (subUrl == null || "".equals(subUrl)) { getContentPane().add(createScrollPane(mainTable, PREFERRED_TABLE_HEIGHT), BorderLayout.CENTER); } else { subTable = new Table(); subTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); initTableListeners(subTable); JScrollPane mainScrollPane = createScrollPane(mainTable, PREFERRED_TABLE_HEIGHT / 2); JScrollPane subScrollPane = createScrollPane(subTable, PREFERRED_TABLE_HEIGHT / 2); JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mainScrollPane, subScrollPane); splitPane.setDividerLocation(PREFERRED_TABLE_HEIGHT / 3); getContentPane().add(splitPane, BorderLayout.CENTER); mainTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { int row = mainTable.getSelectedRow(); if (row != -1) { String key = mainTable.getModel().getValueAt(row, 0) .toString(); loadData(subTable, subUrl, key, false); } } } }); } initSearchFieldListeners(); pack(); setResizable(true); setLocationRelativeTo((Component) workspace.getParentFrame()); } /** * Creates the search field pane and its components. * * @param text the search field text * @return The search field pane. */ private JPanel createSearchFieldPane(String text) { JPanel searchFieldPane = new JPanel(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(0, 0, BORDER_W, BORDER_W); c.gridx = 0; c.gridy = 0; c.gridwidth = 1; searchFieldPane .add(new JLabel(i18n.getString("searchDialog.searchTerms") + ":"), c); c.insets = new Insets(0, 0, BORDER_W, 0); c.gridx = 1; c.weightx = 1; c.fill = GridBagConstraints.HORIZONTAL; searchField = new JTextField(text); searchFieldPane.add(searchField, c); return searchFieldPane; } /** * Creates a scroll pane for a table component. * * @param table the table component * @param height the preferred height of the scroll pane * @return The search results pane component. */ private JScrollPane createScrollPane(Table table, int height) { JScrollPane scrollPane = new JScrollPane(table); scrollPane.setPreferredSize(new Dimension(PREFERRED_TABLE_WIDTH, height)); return scrollPane; } /** * Initializes the search field action listeners. */ private void initSearchFieldListeners() { searchField.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { invokeLoadData(searchField.getText()); } }); searchField.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { selectSearchFieldText(true); } @Override public void focusLost(FocusEvent e) { selectSearchFieldText(false); } }); } /** * Initializes the search results mainTable action listeners. * * @param table the table to add the listeners to */ private void initTableListeners(final Table table) { KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); table.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(enter, SEARCH); table.getActionMap().put(SEARCH, new AbstractAction() { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { submit(table); } }); table.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { submit(table); } } }); } private void submit(Table table) { submittedItem = table.getSelectedRowData(); doOK(); } /** * Selects the search field text. * * @param select specifies if the content of the text field should be selected. */ private void selectSearchFieldText(boolean select) { if (select) { searchField.select(0, searchField.getText().length()); } else { searchField.select(0, 0); } } /** * Calls loadData(String) in a new thread * * @param searchString The search string. */ private void invokeLoadData(final String searchString) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { loadingMask.start(); searchField.setEnabled(false); new Thread(new Runnable() { @Override public void run() { loadData(mainTable, mainUrl, searchString, false); loadingMask.stop(); searchField.setEnabled(true); searchField.requestFocus(); selectSearchFieldText(true); if (tableModel != null) { tableModel.fireTableDataChanged(); } } }).start(); } }); } /** * calls {@link #loadData(Table, String, String, Boolean)} and provides * the main table as value for the table field and true for isFirst * * @param searchString the search string */ public boolean load(String searchString) { return loadData(mainTable, mainUrl, searchString, true); } /** * Initiates a server request with the provided search string; if data is * returned, calls {@link Table#initTableModel(TableData)}. * * @param table the table component displaying the data * @param url the query mainUrl without the search string * @param searchString The search string. * @param isFirst Indicates if this is the first search in the search dialog. * This information can be used in a server script to process the * initial search (based on the selected text in the editor pane) * in a distinct manner. * @return true if data has been successfully loaded and parsed, otherwise false */ private boolean loadData(Table table, String url, String searchString, Boolean isFirst) { TableData result = null; System.out.println(url+searchString); String response = httpUtil.get(user, password, url, searchString, isFirst); if (response != null) { result = jsonUtil.getTableData(response); } if (result != null) { table.initTableModel(result); return true; } else { if (table.getModel() instanceof DefaultTableModel) { ((DefaultTableModel) table.getModel()).setRowCount(0); } } return false; } /** * Gets the data from the subTable's selection (if it exists); if this returns null, * the data from the mainTable's selection is returned * * @return the selected data or null if there is no selection */ private String[] getSelectionData() { String[] result = null; if (subTable != null) { result = subTable.getSelectedRowData(); } if (result != null) { return result; } return mainTable.getSelectedRowData(); } /** * Shows the dialog and returns the value of {@link Table#getSelectedRowData()} if the * the "OK" button was pressed. * * @return the string[] */ public String[] showDialog() { setVisible(true); if (getResult() == RESULT_OK) { if (submittedItem != null) { return submittedItem; } else { return getSelectionData(); } } else { return null; } } }