diff --git a/src/main/gui/net/sf/jailer/ui/StringSearchPanel.form b/src/main/gui/net/sf/jailer/ui/StringSearchPanel.form index 0cdfde5b8..e7f4d234a 100644 --- a/src/main/gui/net/sf/jailer/ui/StringSearchPanel.form +++ b/src/main/gui/net/sf/jailer/ui/StringSearchPanel.form @@ -84,7 +84,7 @@ - + diff --git a/src/main/gui/net/sf/jailer/ui/StringSearchPanel.java b/src/main/gui/net/sf/jailer/ui/StringSearchPanel.java index 8c535f292..2730391e5 100644 --- a/src/main/gui/net/sf/jailer/ui/StringSearchPanel.java +++ b/src/main/gui/net/sf/jailer/ui/StringSearchPanel.java @@ -51,6 +51,8 @@ import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; @@ -441,12 +443,12 @@ public class StringSearchPanel extends javax.swing.JPanel { String text = searchTextField.getText(); boolean withPrefix = !text.startsWith(" "); boolean withSuffix = !text.endsWith(" "); - String searchText = text.trim().toUpperCase(Locale.ENGLISH); DefaultComboBoxModel model = (DefaultComboBoxModel) combobox.getModel(); int size = model.getSize(); for (int i = 0; i < size; ++i) { String item = model.getElementAt(i); if (!item.isEmpty()) { + String searchText = extendesSearchText(text, item); if (!filter || searchText.isEmpty() || withPrefix && withSuffix && item.toUpperCase(Locale.ENGLISH).contains(searchText) @@ -655,8 +657,8 @@ public class StringSearchPanel extends javax.swing.JPanel { fgColor = Color.WHITE; hlColor = "#ff9999"; } - String search = searchTextField.getText().trim().toUpperCase(Locale.ENGLISH); String item = value.toString().trim(); + String search = extendesSearchText(searchTextField.getText(), item); int i = searchTextField.getText().endsWith(" ")? item.toUpperCase(Locale.ENGLISH).lastIndexOf(search) : item.toUpperCase(Locale.ENGLISH).indexOf(search); if (i >= 0) { i = Math.min(i, item.length()); @@ -735,7 +737,7 @@ public class StringSearchPanel extends javax.swing.JPanel { } return render; } - + }); if (metaDataSource == null) { @@ -1021,7 +1023,7 @@ public class StringSearchPanel extends javax.swing.JPanel { jLayeredPane1.setLayout(new java.awt.GridBagLayout()); - searchTextField.setToolTipText("Search criteria.

\nSearch for items that contain the search criteria as:
\n\n\n\n\n
Prefixif it starts with a space
Suffixif it ends with a space
Substringelse
\n\n\n"); + searchTextField.setToolTipText("Search criteria.

\nSearch for items that contain the search criteria as:
\n\n\n\n\n
Prefixif it starts with a space
Suffixif it ends with a space
Substringelse
\n
\n(* = any string, ? = any character)\n"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; @@ -1296,6 +1298,36 @@ public class StringSearchPanel extends javax.swing.JPanel { bottomComponentsPanel.add(component, java.awt.BorderLayout.CENTER); } + private Pattern extSTPattern = null; + private String extSTText = null; + + private String extendesSearchText(String text, String item) { + String searchText = text.toUpperCase(Locale.ENGLISH); + if (!searchText.contains("*") && !searchText.contains("?")) { + return searchText.trim(); + } + + if (!text.equals(extSTText)) { + boolean withPrefix = !text.startsWith(" "); + boolean withSuffix = !text.endsWith(" "); + String reg = (withPrefix? ".*?" : "") + "(\\Q" + + text.trim().replace("?", "\\E.\\Q").replace("*", "\\E.*\\Q") + + "\\E)" + + (withSuffix? ".*?" : ""); + + extSTText = reg; + extSTPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + } + + Matcher matcher = extSTPattern.matcher(item); + + if (matcher.matches()) { + return matcher.group(1); + } else { + return searchText.trim(); + } + } + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel bottomComponentsPanel; private javax.swing.JPanel bottomPanel; diff --git a/src/main/gui/net/sf/jailer/ui/databrowser/BrowserContentPane.java b/src/main/gui/net/sf/jailer/ui/databrowser/BrowserContentPane.java index e1912b3d4..bfc0e1a33 100644 --- a/src/main/gui/net/sf/jailer/ui/databrowser/BrowserContentPane.java +++ b/src/main/gui/net/sf/jailer/ui/databrowser/BrowserContentPane.java @@ -2611,6 +2611,7 @@ public abstract class BrowserContentPane extends javax.swing.JPanel { */ public JPopupMenu createPopupMenu(final JTable contextJTable, final Row row, final int rowIndex, final int x, final int y, boolean navigateFromAllRows, JMenuItem altCopyTCB, final Runnable repaint, final boolean withKeyStroke, boolean withSingleRow, boolean forColumnsTable) { JMenuItem tableFilter = new JCheckBoxMenuItem("Table Filter"); + tableFilter.setIcon(UIUtil.scaleIcon(tableFilter, UIUtil.readImage("/filter.png"))); if (withKeyStroke) { tableFilter.setAccelerator(KS_FILTER); } else { @@ -2895,6 +2896,7 @@ public abstract class BrowserContentPane extends javax.swing.JPanel { } popup.add(tableFilter); JCheckBoxMenuItem editMode = new JCheckBoxMenuItem("Edit Mode"); + setMenuItemName(editMode, "editdetailsitem.png"); editMode.setEnabled(isTableEditable(table)); if (withKeyStroke) { editMode.setAccelerator(KS_EDIT); diff --git a/src/main/gui/net/sf/jailer/ui/databrowser/DesktopAnchorManager.java b/src/main/gui/net/sf/jailer/ui/databrowser/DesktopAnchorManager.java index 210d4ba97..932ff7e3b 100644 --- a/src/main/gui/net/sf/jailer/ui/databrowser/DesktopAnchorManager.java +++ b/src/main/gui/net/sf/jailer/ui/databrowser/DesktopAnchorManager.java @@ -36,6 +36,7 @@ import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; +import javax.swing.Timer; import javax.swing.event.InternalFrameEvent; import javax.swing.event.InternalFrameListener; import javax.swing.plaf.basic.BasicInternalFrameUI; @@ -58,17 +59,18 @@ public abstract class DesktopAnchorManager { private RowBrowser currentBrowser; private RowBrowser newestBrowser; private int height = 5 * 18; - private boolean useBuffer = true; - private final static int MAX_RETENDION = 800; + private final static int MAX_RETENDION = 1200; @SuppressWarnings("serial") public DesktopAnchorManager(JPanel topLayerPanel) { this.anchorPanel = new JPanel(null) { @Override public void paint(Graphics g) { - if (useBuffer) { + if (showedAt != null) { + double r = 0.75f; + double t = System.currentTimeMillis() - showedAt - MAX_RETENDION * r; Graphics2D g2 = (Graphics2D) g.create(); - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) ((1 - Math.max(0f, Math.min(1f, ((t / (MAX_RETENDION * (1 - r))))))) * 0.5f))); super.paint(g2); g2.dispose(); } else { @@ -116,12 +118,11 @@ public abstract class DesktopAnchorManager { } @Override public void mouseExited(MouseEvent e) { - showedAt = System.currentTimeMillis(); + initShowedAt(); } @Override public void mouseEntered(MouseEvent e) { showedAt = null; - useBuffer = false; anchorPanel.repaint(); } @Override @@ -161,12 +162,11 @@ public abstract class DesktopAnchorManager { } @Override public void mouseExited(MouseEvent e) { - showedAt = System.currentTimeMillis(); + initShowedAt(); } @Override public void mouseEntered(MouseEvent e) { showedAt = null; - useBuffer = false; anchorPanel.repaint(); } @Override @@ -305,7 +305,6 @@ public abstract class DesktopAnchorManager { if (disabledUntil != null && disabledUntil > System.currentTimeMillis()) { return; } - useBuffer = true; anchorPanel.removeAll(); anchorPanel.add(anchorButton); currentBrowser = tableBrowser; @@ -325,7 +324,26 @@ public abstract class DesktopAnchorManager { anchorPanel.setVisible(true); topLayerPanel.setVisible(true); height = anchorPanel.getHeight(); + initShowedAt(); + } + + /** + * + */ + private void initShowedAt() { showedAt = System.currentTimeMillis(); + int delay = 100; + Timer timer = new Timer(delay, null); + timer.addActionListener(e -> { + if (showedAt != null && anchorPanel.isVisible()) { + anchorPanel.paintImmediately(0, 0, anchorPanel.getWidth(), anchorPanel.getHeight()); + } else { + timer.stop(); + } + }); + timer.setRepeats(true); + timer.setInitialDelay(delay); + timer.start(); } void reset() { diff --git a/src/main/gui/net/sf/jailer/ui/databrowser/FullTextSearchPanel.form b/src/main/gui/net/sf/jailer/ui/databrowser/FullTextSearchPanel.form index a9112bdcd..02598d0a0 100644 --- a/src/main/gui/net/sf/jailer/ui/databrowser/FullTextSearchPanel.form +++ b/src/main/gui/net/sf/jailer/ui/databrowser/FullTextSearchPanel.form @@ -31,7 +31,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -51,7 +51,7 @@ - + diff --git a/src/main/gui/net/sf/jailer/ui/databrowser/FullTextSearchPanel.java b/src/main/gui/net/sf/jailer/ui/databrowser/FullTextSearchPanel.java index c1008495d..b3a0ec5e5 100644 --- a/src/main/gui/net/sf/jailer/ui/databrowser/FullTextSearchPanel.java +++ b/src/main/gui/net/sf/jailer/ui/databrowser/FullTextSearchPanel.java @@ -30,6 +30,8 @@ import java.util.Locale; import java.util.Map; import java.util.NavigableMap; import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.swing.BorderFactory; import javax.swing.ImageIcon; @@ -258,6 +260,36 @@ public class FullTextSearchPanel extends javax.swing.JPanel { updateErrorState(); } + private Pattern extSTPattern = null; + private String extSTText = null; + + private String extendesSearchText(String text, String item) { + String searchText = text.toUpperCase(Locale.ENGLISH); + if (!searchText.contains("*") && !searchText.contains("?")) { + return searchText.trim(); + } + + if (!text.equals(extSTText)) { + boolean withPrefix = !text.startsWith(" "); + boolean withSuffix = !text.endsWith(" "); + String reg = (withPrefix? ".*?" : "") + "(\\Q" + + text.trim().replace("?", "\\E.\\Q").replace("*", "\\E.*\\Q") + + "\\E)" + + (withSuffix? ".*?" : ""); + + extSTText = reg; + extSTPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + } + + Matcher matcher = extSTPattern.matcher(item); + + if (matcher.matches()) { + return matcher.group(1); + } else { + return searchText.trim(); + } + } + private void update(String searchText, boolean setCurrentPosition) { if (inUpdate) { return; @@ -297,6 +329,9 @@ public class FullTextSearchPanel extends javax.swing.JPanel { for (int y = 0; y < rc; ++y) { for (int x = 0; x < cc; ++x) { Object v = dm.getValueAt(y, x); + if (v != null) { + searchTextUC = extendesSearchText(searchText, v.toString().trim()); + } if (v != null && !v.toString().toUpperCase(Locale.ENGLISH).contains(searchTextUC)) { continue; } @@ -326,8 +361,8 @@ public class FullTextSearchPanel extends javax.swing.JPanel { } i += offset; i = Math.min(i, value.length()); - if (i + searchTextTrim.length() <= value.length()) { - markedValue = UIUtil.toHTMLFragment(value.substring(0, i), 0, false) + "" + UIUtil.toHTMLFragment(value.substring(i, i + searchTextTrim.length()), 0, false) + "" + UIUtil.toHTMLFragment(value.substring(i + searchTextTrim.length()), 0, false); + if (i + searchTextUC.length() <= value.length()) { + markedValue = UIUtil.toHTMLFragment(value.substring(0, i), 0, false) + "" + UIUtil.toHTMLFragment(value.substring(i, i + searchTextUC.length()), 0, false) + "" + UIUtil.toHTMLFragment(value.substring(i + searchTextUC.length()), 0, false); } if (markedValue == null) { markedValue = "" + UIUtil.toHTMLFragment(value, 0, false) + ""; @@ -548,21 +583,21 @@ public class FullTextSearchPanel extends javax.swing.JPanel { jToolBar1.setFloatable(false); jToolBar1.setRollover(true); - searchField.setToolTipText("Search criteria.

Search for items that contain the search criteria as:
Prefixif it starts with a space
Suffixif it ends with a space
Substringelse
"); + searchField.setToolTipText("Search criteria.

\nSearch for items that contain the search criteria as:
\n\n\n\n\n
Prefixif it starts with a space
Suffixif it ends with a space
Substringelse
\n
\n(* = any string, ? = any character)\n"); jToolBar1.add(searchField); jLabel1.setText(" "); jToolBar1.add(jLabel1); prevButton.setText("Previous"); - prevButton.setToolTipText("Find previous occurrence."); + prevButton.setToolTipText("Find previous occurrence"); prevButton.setFocusable(false); prevButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); prevButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); jToolBar1.add(prevButton); nextButton.setText("Next"); - nextButton.setToolTipText("Find next occurrence."); + nextButton.setToolTipText("Find next occurrence"); nextButton.setFocusable(false); nextButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); nextButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); @@ -604,7 +639,7 @@ public class FullTextSearchPanel extends javax.swing.JPanel { this.transposedTable = transposedTable; } - // Variables declaration - do not modify//GEN-BEGIN:variables + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton closeButton; private javax.swing.JLabel counterLabel; private javax.swing.JLabel jLabel1;