PageRenderTime 800ms CodeModel.GetById 697ms app.highlight 82ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/search/SearchDialog.java

#
Java | 1058 lines | 774 code | 159 blank | 125 comment | 109 complexity | 7ba891ec10c97c5a67495a149f90b228 MD5 | raw file
   1/*
   2 * SearchDialog.java - Search and replace dialog
   3 * :tabSize=8:indentSize=8:noTabs=false:
   4 * :folding=explicit:collapseFolds=1:
   5 *
   6 * Copyright (C) 1998, 2004 Slava Pestov
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License
  10 * as published by the Free Software Foundation; either version 2
  11 * of the License, or any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21 */
  22
  23package org.gjt.sp.jedit.search;
  24
  25//{{{ Imports
  26import javax.swing.border.*;
  27import javax.swing.*;
  28
  29import java.awt.*;
  30import java.awt.event.*;
  31import java.io.File;
  32import java.util.HashMap;
  33import org.gjt.sp.jedit.browser.VFSBrowser;
  34import org.gjt.sp.jedit.gui.*;
  35import org.gjt.sp.jedit.io.*;
  36import org.gjt.sp.jedit.msg.SearchSettingsChanged;
  37import org.gjt.sp.jedit.msg.ViewUpdate;
  38import org.gjt.sp.jedit.*;
  39//}}}
  40
  41/**
  42 * Search and replace dialog.
  43 * @author Slava Pestov
  44 * @version $Id: SearchDialog.java 5425 2006-05-24 18:39:23Z ezust $
  45 */
  46public class SearchDialog extends EnhancedDialog implements EBComponent
  47{
  48	//{{{ Constants
  49	/**
  50	 * Default file set.
  51	 * @since jEdit 3.2pre2
  52	 */
  53	public static final int CURRENT_BUFFER = 0;
  54	public static final int ALL_BUFFERS = 1;
  55	public static final int DIRECTORY = 2;
  56	//}}}
  57
  58	//{{{ getSearchDialog() method
  59	public static SearchDialog getSearchDialog(View view)
  60	{
  61		if(Debug.DISABLE_SEARCH_DIALOG_POOL)
  62			return new SearchDialog(view);
  63		else
  64			return (SearchDialog)viewHash.get(view);
  65	} //}}}
  66
  67	//{{{ preloadSearchDialog() method
  68	/**
  69	 * Preloads the search dialog for the given for so that it can be
  70	 * quickly displayed later.
  71	 * @since jEdit 4.2pre3
  72	 */
  73	public static void preloadSearchDialog(View view)
  74	{
  75		if(Debug.DISABLE_SEARCH_DIALOG_POOL)
  76			return;
  77
  78		SearchDialog dialog = new SearchDialog(view);
  79		viewHash.put(view,dialog);
  80	} //}}}
  81
  82	//{{{ showSearchDialog() method
  83	/**
  84	 * Displays a search and replace dialog box, reusing an existing one
  85	 * if necessary.
  86	 * @param view The view
  87	 * @param searchString The search string
  88	 * @param searchIn One of CURRENT_BUFFER, ALL_BUFFERS, or DIRECTORY
  89	 * @since jEdit 4.0pre6
  90	 */
  91	public static void showSearchDialog(View view, String searchString,
  92		int searchIn)
  93	{
  94		final SearchDialog dialog = getSearchDialog(view);
  95
  96		dialog.setSearchString(searchString,searchIn);
  97
  98		// ugly workaround
  99		if(OperatingSystem.isUnix() && !OperatingSystem.isMacOS())
 100			dialog.setVisible(false);
 101
 102		// I'm not sure if calling requestFocus() is strictly necessary
 103		// (focus looks fine without this, on Linux at least), but
 104		// it doesn't hurt to leave it here.
 105		SwingUtilities.invokeLater(new Runnable() {
 106			public void run() {
 107				dialog.toFront();
 108				dialog.find.requestFocus();
 109			}
 110		});
 111		dialog.setVisible(true);
 112	} //}}}
 113
 114	//{{{ setSearchString() method
 115	/**
 116	 * Sets the search string.
 117	 * @since jEdit 4.0pre5
 118	 */
 119	public void setSearchString(String searchString, int searchIn)
 120	{
 121		find.setText(null);
 122		replace.setText(null);
 123
 124		if(searchString == null)
 125			searchCurrentBuffer.setSelected(true);
 126		else
 127		{
 128			if(searchString.indexOf('\n') == -1)
 129			{
 130				if(SearchAndReplace.getRegexp())
 131				{
 132					find.setText(SearchAndReplace.escapeRegexp(
 133						searchString,true));
 134				}
 135				else
 136					find.setText(searchString);
 137				find.selectAll();
 138				searchCurrentBuffer.setSelected(true);
 139			}
 140			else if(searchIn == CURRENT_BUFFER)
 141			{
 142				searchSelection.setSelected(true);
 143				hyperSearch.setSelected(true);
 144			}
 145		}
 146
 147		if(searchIn == CURRENT_BUFFER)
 148		{
 149			if(!searchSelection.isSelected())
 150			{
 151				// might be already selected, see above.
 152				searchCurrentBuffer.setSelected(true);
 153
 154				/* this property is only loaded and saved if
 155				 * the 'current buffer' file set is selected.
 156				 * otherwise, it defaults to on. */
 157				hyperSearch.setSelected(jEdit.getBooleanProperty(
 158					"search.hypersearch.toggle"));
 159			}
 160		}
 161		else if(searchIn == ALL_BUFFERS)
 162		{
 163			searchAllBuffers.setSelected(true);
 164			hyperSearch.setSelected(true);
 165		}
 166		else if(searchIn == DIRECTORY)
 167		{
 168			SearchFileSet fileset = SearchAndReplace.getSearchFileSet();
 169
 170			if(fileset instanceof DirectoryListSet)
 171			{
 172				filter.setText(((DirectoryListSet)fileset)
 173					.getFileFilter());
 174				directory.setText(((DirectoryListSet)fileset)
 175					.getDirectory());
 176				searchSubDirectories.setSelected(((DirectoryListSet)fileset)
 177					.isRecursive());
 178			}
 179
 180			hyperSearch.setSelected(true);
 181			searchDirectory.setSelected(true);
 182		}
 183
 184		updateEnabled();
 185	} //}}}
 186
 187	//{{{ ok() method
 188	public void ok()
 189	{
 190		try
 191		{
 192			setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
 193
 194			if(!save(false))
 195				return;
 196
 197			if(searchSelection.isSelected()
 198				&& view.getTextArea().getSelectionCount() == 0)
 199			{
 200				GUIUtilities.error(view,"search-no-selection",null);
 201				return;
 202			}
 203
 204			if(hyperSearch.isSelected() || searchSelection.isSelected())
 205			{
 206				if(SearchAndReplace.hyperSearch(view,
 207					searchSelection.isSelected()))
 208					closeOrKeepDialog();
 209			}
 210			else
 211			{
 212				if(SearchAndReplace.find(view))
 213					closeOrKeepDialog();
 214				else
 215				{
 216					toFront();
 217					requestFocus();
 218					find.requestFocus();
 219				}
 220			}
 221		}
 222		finally
 223		{
 224			setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
 225		}
 226	} //}}}
 227
 228	//{{{ cancel() method
 229	public void cancel()
 230	{
 231		save(true);
 232		GUIUtilities.saveGeometry(this,"search");
 233		setVisible(false);
 234	} //}}}
 235
 236	//{{{ handleMessage() method
 237	public void handleMessage(EBMessage msg)
 238	{
 239		if(msg instanceof SearchSettingsChanged)
 240		{
 241			if(!saving)
 242				load();
 243		}
 244	} //}}}
 245
 246	//{{{ dispose() method
 247	public void dispose()
 248	{
 249		EditBus.removeFromBus(this);
 250		viewHash.remove(view);
 251		super.dispose();
 252	} //}}}
 253
 254	//{{{ Private members
 255
 256	private static HashMap viewHash = new HashMap();
 257
 258	//{{{ Instance variables
 259	private View view;
 260
 261	// fields
 262	private HistoryTextArea find, replace;
 263
 264	private JRadioButton stringReplace, beanShellReplace;
 265
 266	// search settings
 267	private JCheckBox keepDialog, ignoreCase, regexp, hyperSearch,
 268		wrap;
 269	private JRadioButton searchBack, searchForward;
 270	private JRadioButton searchSelection, searchCurrentBuffer,
 271		searchAllBuffers, searchDirectory;
 272
 273	// multifile settings
 274	private HistoryTextField filter, directory;
 275	private JCheckBox searchSubDirectories;
 276	private JCheckBox skipBinaryFiles;
 277	private JCheckBox skipHidden;
 278	
 279	private JButton choose;
 280	private JButton synchronize;
 281
 282	// buttons
 283	private JButton findBtn, /* replaceBtn, */ replaceAndFindBtn, replaceAllBtn,
 284		closeBtn;
 285
 286	private boolean saving;
 287	//}}}
 288
 289	//{{{ SearchDialog constructor
 290	/**
 291	 * Creates a new search and replace dialog box.
 292	 * @param view The view
 293	 * @param searchString The search string
 294	 */
 295	private SearchDialog(View view)
 296	{
 297		super(view,jEdit.getProperty("search.title"),false);
 298
 299		this.view = view;
 300
 301		JPanel content = new JPanel(new BorderLayout());
 302		content.setBorder(new EmptyBorder(0,12,12,12));
 303		setContentPane(content);
 304
 305		JPanel centerPanel = new JPanel(new BorderLayout());
 306		centerPanel.add(BorderLayout.CENTER,createFieldPanel());
 307		centerPanel.add(BorderLayout.SOUTH,createSearchSettingsPanel());
 308		content.add(BorderLayout.CENTER,centerPanel);
 309		content.add(BorderLayout.SOUTH,createMultiFilePanel());
 310
 311		content.add(BorderLayout.EAST,createButtonsPanel());
 312
 313		pack();
 314		jEdit.unsetProperty("search.width");
 315		jEdit.unsetProperty("search.d-width");
 316		jEdit.unsetProperty("search.height");
 317		jEdit.unsetProperty("search.d-height");
 318		GUIUtilities.loadGeometry(this,"search");
 319
 320		load();
 321
 322		EditBus.addToBus(this);
 323	} //}}}
 324
 325	//{{{ createFindLabelAndField() method
 326	private void createFindLabelAndField(JPanel fieldPanel,
 327		GridBagConstraints cons)
 328	{
 329		JLabel label = new JLabel(jEdit.getProperty("search.find"));
 330		label.setDisplayedMnemonic(jEdit.getProperty("search.find.mnemonic")
 331			.charAt(0));
 332		find = new HistoryTextArea("find");
 333		find.setColumns(25);
 334
 335		label.setLabelFor(find);
 336		label.setBorder(new EmptyBorder(12,0,2,0));
 337
 338		cons.gridx = 0;
 339		cons.weightx = 0.0f;
 340		cons.weighty = 0.0f;
 341		fieldPanel.add(label,cons);
 342		cons.gridy++;
 343		cons.weightx = 1.0f;
 344		cons.weighty = 1.0f;
 345		fieldPanel.add(new JScrollPane(find),cons);
 346		cons.gridy++;
 347	} //}}}
 348
 349	//{{{ createReplaceLabelAndField() method
 350	private void createReplaceLabelAndField(JPanel fieldPanel,
 351		GridBagConstraints cons)
 352	{
 353		JLabel label = new JLabel(jEdit.getProperty("search.replace"));
 354		label.setDisplayedMnemonic(jEdit.getProperty("search.replace.mnemonic")
 355			.charAt(0));
 356		label.setBorder(new EmptyBorder(12,0,0,0));
 357
 358		cons.gridx = 0;
 359		cons.weightx = 0.0f;
 360		cons.weighty = 0.0f;
 361		fieldPanel.add(label,cons);
 362		cons.gridy++;
 363
 364		ButtonGroup grp = new ButtonGroup();
 365		ReplaceActionHandler replaceActionHandler = new ReplaceActionHandler();
 366
 367		// we use a custom JRadioButton subclass that returns
 368		// false for isFocusTraversable() so that the user can
 369		// tab from the search field to the replace field with
 370		// one keystroke
 371
 372		stringReplace = new MyJRadioButton(jEdit.getProperty(
 373			"search.string-replace-btn"));
 374		stringReplace.addActionListener(replaceActionHandler);
 375		grp.add(stringReplace);
 376		cons.gridwidth = 1;
 377		fieldPanel.add(stringReplace,cons);
 378		cons.gridx++;
 379		cons.insets = new Insets(0,12,0,0);
 380
 381		beanShellReplace = new MyJRadioButton(jEdit.getProperty(
 382			"search.beanshell-replace-btn"));
 383		beanShellReplace.addActionListener(replaceActionHandler);
 384		grp.add(beanShellReplace);
 385		fieldPanel.add(beanShellReplace,cons);
 386		cons.gridx = 0;
 387		cons.gridwidth = 2;
 388		cons.insets = new Insets(0,0,0,0);
 389
 390		replace = new HistoryTextArea("replace");
 391		label.setLabelFor(replace);
 392
 393		cons.gridx = 0;
 394		cons.gridy++;
 395		cons.weightx = 1.0f;
 396		cons.weighty = 1.0f;
 397		fieldPanel.add(new JScrollPane(replace),cons);
 398		cons.gridy++;
 399	} //}}}
 400
 401	//{{{ createFieldPanel() method
 402	private JPanel createFieldPanel()
 403	{
 404		JPanel fieldPanel = new JPanel(new GridBagLayout());
 405		fieldPanel.setBorder(new EmptyBorder(0,0,12,12));
 406
 407		GridBagConstraints cons = new GridBagConstraints();
 408		cons.fill = GridBagConstraints.BOTH;
 409		cons.gridy = 0;
 410		cons.gridwidth = 2;
 411
 412		createFindLabelAndField(fieldPanel,cons);
 413		createReplaceLabelAndField(fieldPanel,cons);
 414
 415		return fieldPanel;
 416	} //}}}
 417
 418	//{{{ createSearchSettingsPanel() method
 419	private JPanel createSearchSettingsPanel()
 420	{
 421		JPanel searchSettings = new JPanel(new VariableGridLayout(
 422			VariableGridLayout.FIXED_NUM_COLUMNS,3));
 423		searchSettings.setBorder(new EmptyBorder(0,0,12,12));
 424
 425		SettingsActionHandler actionHandler = new SettingsActionHandler();
 426		ButtonGroup fileset = new ButtonGroup();
 427		ButtonGroup direction = new ButtonGroup();
 428
 429		searchSettings.add(new JLabel(jEdit.getProperty("search.fileset")));
 430
 431		searchSettings.add(new JLabel(jEdit.getProperty("search.settings")));
 432
 433		searchSettings.add(new JLabel(jEdit.getProperty("search.direction")));
 434
 435		searchSelection = new JRadioButton(jEdit.getProperty("search.selection"));
 436		searchSelection.setMnemonic(jEdit.getProperty("search.selection.mnemonic")
 437			.charAt(0));
 438		fileset.add(searchSelection);
 439		searchSettings.add(searchSelection);
 440		searchSelection.addActionListener(actionHandler);
 441
 442		keepDialog = new JCheckBox(jEdit.getProperty("search.keep"));
 443		keepDialog.setMnemonic(jEdit.getProperty("search.keep.mnemonic")
 444			.charAt(0));
 445		searchSettings.add(keepDialog);
 446
 447		searchBack = new JRadioButton(jEdit.getProperty("search.back"));
 448		searchBack.setMnemonic(jEdit.getProperty("search.back.mnemonic")
 449			.charAt(0));
 450		direction.add(searchBack);
 451		searchSettings.add(searchBack);
 452		searchBack.addActionListener(actionHandler);
 453
 454		searchCurrentBuffer = new JRadioButton(jEdit.getProperty("search.current"));
 455		searchCurrentBuffer.setMnemonic(jEdit.getProperty("search.current.mnemonic")
 456			.charAt(0));
 457		fileset.add(searchCurrentBuffer);
 458		searchSettings.add(searchCurrentBuffer);
 459		searchCurrentBuffer.addActionListener(actionHandler);
 460
 461		ignoreCase = new JCheckBox(jEdit.getProperty("search.case"));
 462		ignoreCase.setMnemonic(jEdit.getProperty("search.case.mnemonic")
 463			.charAt(0));
 464		searchSettings.add(ignoreCase);
 465		ignoreCase.addActionListener(actionHandler);
 466
 467		searchForward = new JRadioButton(jEdit.getProperty("search.forward"));
 468		searchForward.setMnemonic(jEdit.getProperty("search.forward.mnemonic")
 469			.charAt(0));
 470		direction.add(searchForward);
 471		searchSettings.add(searchForward);
 472		searchForward.addActionListener(actionHandler);
 473
 474		searchAllBuffers = new JRadioButton(jEdit.getProperty("search.all"));
 475		searchAllBuffers.setMnemonic(jEdit.getProperty("search.all.mnemonic")
 476			.charAt(0));
 477		fileset.add(searchAllBuffers);
 478		searchSettings.add(searchAllBuffers);
 479		searchAllBuffers.addActionListener(actionHandler);
 480
 481		regexp = new JCheckBox(jEdit.getProperty("search.regexp"));
 482		regexp.setMnemonic(jEdit.getProperty("search.regexp.mnemonic")
 483			.charAt(0));
 484		searchSettings.add(regexp);
 485		regexp.addActionListener(actionHandler);
 486
 487		wrap = new JCheckBox(jEdit.getProperty("search.wrap"));
 488		wrap.setMnemonic(jEdit.getProperty("search.wrap.mnemonic")
 489			.charAt(0));
 490		searchSettings.add(wrap);
 491		wrap.addActionListener(actionHandler);
 492
 493		searchDirectory = new JRadioButton(jEdit.getProperty("search.directory"));
 494		searchDirectory.setMnemonic(jEdit.getProperty("search.directory.mnemonic")
 495			.charAt(0));
 496		fileset.add(searchDirectory);
 497		searchSettings.add(searchDirectory);
 498		searchDirectory.addActionListener(actionHandler);
 499
 500		hyperSearch = new JCheckBox(jEdit.getProperty("search.hypersearch"));
 501		hyperSearch.setMnemonic(jEdit.getProperty("search.hypersearch.mnemonic")
 502			.charAt(0));
 503		searchSettings.add(hyperSearch);
 504		hyperSearch.addActionListener(actionHandler);
 505
 506		return searchSettings;
 507	} //}}}
 508
 509	//{{{ createMultiFilePanel() method
 510	private JPanel createMultiFilePanel()
 511	{
 512		JPanel multifile = new JPanel();
 513
 514		GridBagLayout layout = new GridBagLayout();
 515		multifile.setLayout(layout);
 516
 517		GridBagConstraints cons = new GridBagConstraints();
 518		cons.gridy = cons.gridwidth = cons.gridheight = 1;
 519		cons.anchor = GridBagConstraints.WEST;
 520		cons.fill = GridBagConstraints.HORIZONTAL;
 521
 522		MultiFileActionHandler actionListener = new MultiFileActionHandler();
 523		filter = new HistoryTextField("search.filter");
 524		filter.addActionListener(actionListener);
 525
 526		cons.insets = new Insets(0,0,3,0);
 527
 528		JLabel label = new JLabel(jEdit.getProperty("search.filterField"),
 529			SwingConstants.RIGHT);
 530		label.setBorder(new EmptyBorder(0,0,0,12));
 531		label.setDisplayedMnemonic(jEdit.getProperty("search.filterField.mnemonic")
 532			.charAt(0));
 533		label.setLabelFor(filter);
 534		cons.weightx = 0.0f;
 535		layout.setConstraints(label,cons);
 536		multifile.add(label);
 537
 538		cons.gridwidth = 2;
 539		cons.insets = new Insets(0,0,3,6);
 540		cons.weightx = 1.0f;
 541		layout.setConstraints(filter,cons);
 542		multifile.add(filter);
 543
 544		cons.gridwidth = 1;
 545		cons.weightx = 0.0f;
 546		cons.insets = new Insets(0,0,3,0);
 547
 548		synchronize = new JButton(jEdit.getProperty(
 549			"search.synchronize"));
 550		synchronize.setMnemonic(jEdit.getProperty(
 551			"search.synchronize.mnemonic")
 552			.charAt(0));
 553		synchronize.addActionListener(actionListener);
 554		layout.setConstraints(synchronize,cons);
 555		multifile.add(synchronize);
 556
 557		cons.gridy++;
 558
 559		directory = new HistoryTextField("search.directory");
 560		directory.setColumns(25);
 561		directory.addActionListener(actionListener);
 562
 563		label = new JLabel(jEdit.getProperty("search.directoryField"),
 564			SwingConstants.RIGHT);
 565		label.setBorder(new EmptyBorder(0,0,0,12));
 566
 567		label.setDisplayedMnemonic(jEdit.getProperty("search.directoryField.mnemonic")
 568			.charAt(0));
 569		label.setLabelFor(directory);
 570		cons.insets = new Insets(0,0,3,0);
 571		cons.weightx = 0.0f;
 572		layout.setConstraints(label,cons);
 573		multifile.add(label);
 574
 575		cons.insets = new Insets(0,0,3,6);
 576		cons.weightx = 1.0f;
 577		cons.gridwidth = 2;
 578		layout.setConstraints(directory,cons);
 579		multifile.add(directory);
 580
 581		choose = new JButton(jEdit.getProperty("search.choose"));
 582		choose.setMnemonic(jEdit.getProperty("search.choose.mnemonic")
 583			.charAt(0));
 584		cons.insets = new Insets(0,0,3,0);
 585		cons.weightx = 0.0f;
 586		cons.gridwidth = 1;
 587		layout.setConstraints(choose,cons);
 588		multifile.add(choose);
 589		choose.addActionListener(actionListener);
 590
 591		cons.insets = new Insets(0,0,0,0);
 592		cons.gridy++;
 593		cons.gridwidth = 3;
 594
 595		JPanel dirCheckBoxPanel = new JPanel();
 596 		searchSubDirectories = new JCheckBox(jEdit.getProperty(
 597 			"search.subdirs"));
 598 		String mnemonic = jEdit.getProperty(
 599			"search.subdirs.mnemonic");
 600		searchSubDirectories.setMnemonic(mnemonic.charAt(0));
 601		searchSubDirectories.setSelected(jEdit.getBooleanProperty("search.subdirs.toggle"));
 602		skipHidden = new JCheckBox(jEdit.getProperty("search.skipHidden"));
 603		skipHidden.setSelected(jEdit.getBooleanProperty("search.skipHidden.toggle", true));
 604		skipBinaryFiles = new JCheckBox(jEdit.getProperty("search.skipBinary"));
 605		skipBinaryFiles.setSelected(jEdit.getBooleanProperty("search.skipBinary.toggle", true));
 606		dirCheckBoxPanel.add(searchSubDirectories);
 607		dirCheckBoxPanel.add(skipHidden);
 608		dirCheckBoxPanel.add(skipBinaryFiles);
 609
 610		cons.insets = new Insets(0, 0, 0, 0);
 611		cons.gridy++;
 612		cons.gridwidth = 4;
 613		layout.setConstraints(dirCheckBoxPanel, cons);
 614
 615 		multifile.add(dirCheckBoxPanel);
 616
 617		return multifile;
 618	} //}}}
 619
 620	//{{{ createButtonsPanel() method
 621	private Box createButtonsPanel()
 622	{
 623		Box box = new Box(BoxLayout.Y_AXIS);
 624
 625		ButtonActionHandler actionHandler = new ButtonActionHandler();
 626
 627		box.add(Box.createVerticalStrut(12));
 628
 629		JPanel grid = new JPanel(new GridLayout(5,1,0,12));
 630
 631		findBtn = new JButton(jEdit.getProperty("search.findBtn"));
 632		/* findBtn.setMnemonic(jEdit.getProperty("search.findBtn.mnemonic")
 633			.charAt(0)); */
 634		getRootPane().setDefaultButton(findBtn);
 635		grid.add(findBtn);
 636		findBtn.addActionListener(actionHandler);
 637
 638		/* replaceBtn = new JButton(jEdit.getProperty("search.replaceBtn"));
 639		replaceBtn.setMnemonic(jEdit.getProperty("search.replaceBtn.mnemonic")
 640			.charAt(0));
 641		grid.add(replaceBtn);
 642		replaceBtn.addActionListener(actionHandler); */
 643
 644		replaceAndFindBtn = new JButton(jEdit.getProperty("search.replaceAndFindBtn"));
 645		replaceAndFindBtn.setMnemonic(jEdit.getProperty("search.replaceAndFindBtn.mnemonic")
 646			.charAt(0));
 647		grid.add(replaceAndFindBtn);
 648		replaceAndFindBtn.addActionListener(actionHandler);
 649
 650		replaceAllBtn = new JButton(jEdit.getProperty("search.replaceAllBtn"));
 651		replaceAllBtn.setMnemonic(jEdit.getProperty("search.replaceAllBtn.mnemonic")
 652			.charAt(0));
 653		grid.add(replaceAllBtn);
 654		replaceAllBtn.addActionListener(actionHandler);
 655
 656		closeBtn = new JButton(jEdit.getProperty("common.close"));
 657		grid.add(closeBtn);
 658		closeBtn.addActionListener(actionHandler);
 659
 660		grid.setMaximumSize(grid.getPreferredSize());
 661
 662		box.add(grid);
 663		box.add(Box.createGlue());
 664
 665		return box;
 666	} //}}}
 667
 668	//{{{ updateEnabled() method
 669	private void updateEnabled()
 670	{
 671		wrap.setEnabled(!hyperSearch.isSelected()
 672			&& !searchSelection.isSelected());
 673
 674		boolean reverseEnabled = !hyperSearch.isSelected()
 675			&& searchCurrentBuffer.isSelected()
 676			&& !regexp.isSelected();
 677		searchBack.setEnabled(reverseEnabled);
 678		searchForward.setEnabled(reverseEnabled);
 679		if(!reverseEnabled)
 680			searchForward.setSelected(true);
 681
 682		filter.setEnabled(searchAllBuffers.isSelected()
 683			|| searchDirectory.isSelected());
 684
 685		boolean searchDirs = searchDirectory.isSelected();
 686		directory.setEnabled(searchDirs);
 687		choose.setEnabled(searchDirs);
 688		searchSubDirectories.setEnabled(searchDirs);
 689		skipHidden.setEnabled(searchDirs);
 690		skipBinaryFiles.setEnabled(searchDirs);
 691		
 692		synchronize.setEnabled(searchAllBuffers.isSelected()
 693			|| searchDirectory.isSelected());
 694
 695		findBtn.setEnabled(!searchSelection.isSelected()
 696			|| hyperSearch.isSelected());
 697		replaceAndFindBtn.setEnabled(!hyperSearch.isSelected()
 698			&& !searchSelection.isSelected());
 699	} //}}}
 700
 701	//{{{ save() method
 702	/**
 703	 * @param cancel If true, we don't bother the user with warning messages
 704	 */
 705	private boolean save(boolean cancel)
 706	{
 707		try
 708		{
 709			// prevents us from handling SearchSettingsChanged
 710			// as a result of below
 711			saving = true;
 712			SearchAndReplace.setIgnoreCase(ignoreCase.isSelected());
 713			SearchAndReplace.setRegexp(regexp.isSelected());
 714			SearchAndReplace.setReverseSearch(searchBack.isSelected());
 715			SearchAndReplace.setAutoWrapAround(wrap.isSelected());
 716			jEdit.setBooleanProperty("search.subdirs.toggle", searchSubDirectories.isSelected());
 717			jEdit.setBooleanProperty("search.skipHidden.toggle", skipHidden.isSelected());
 718			jEdit.setBooleanProperty("search.skipBinary.toggle", skipBinaryFiles.isSelected());
 719
 720			String filter = this.filter.getText();
 721			this.filter.addCurrentToHistory();
 722			if(filter.length() == 0)
 723				filter = "*";
 724
 725			SearchFileSet fileset = SearchAndReplace.getSearchFileSet();
 726
 727			boolean recurse = searchSubDirectories.isSelected();
 728
 729			if(searchSelection.isSelected())
 730				fileset = new CurrentBufferSet();
 731			else if(searchCurrentBuffer.isSelected())
 732			{
 733				fileset = new CurrentBufferSet();
 734
 735				jEdit.setBooleanProperty("search.hypersearch.toggle",
 736					hyperSearch.isSelected());
 737			}
 738			else if(searchAllBuffers.isSelected())
 739				fileset = new AllBufferSet(filter);
 740			else if(searchDirectory.isSelected())
 741			{
 742				String directory = this.directory.getText();
 743				this.directory.addCurrentToHistory();
 744				directory = MiscUtilities.constructPath(
 745					view.getBuffer().getDirectory(),directory);
 746
 747				if((VFSManager.getVFSForPath(directory).getCapabilities()
 748					& VFS.LOW_LATENCY_CAP) == 0)
 749				{
 750					if(cancel)
 751						return false;
 752
 753					int retVal = GUIUtilities.confirm(
 754						SearchDialog.this,"remote-dir-search",
 755						null,JOptionPane.YES_NO_OPTION,
 756						JOptionPane.WARNING_MESSAGE);
 757					if(retVal != JOptionPane.YES_OPTION)
 758						return false;
 759				}
 760
 761				if(fileset instanceof DirectoryListSet)
 762				{
 763					DirectoryListSet dset = (DirectoryListSet)fileset;
 764					dset.setDirectory(directory);
 765					dset.setFileFilter(filter);
 766					dset.setRecursive(recurse);
 767					EditBus.send(new SearchSettingsChanged(null));
 768				}
 769				else
 770					fileset = new DirectoryListSet(directory,filter,recurse);
 771			}
 772			else
 773			{
 774				// can't happen
 775				fileset = null;
 776			}
 777
 778			jEdit.setBooleanProperty("search.subdirs.toggle",
 779				recurse);
 780			jEdit.setBooleanProperty("search.keepDialog.toggle",
 781				keepDialog.isSelected());
 782
 783			SearchAndReplace.setSearchFileSet(fileset);
 784
 785			replace.addCurrentToHistory();
 786			SearchAndReplace.setReplaceString(replace.getText());
 787
 788			if(find.getText().length() == 0)
 789			{
 790				if(!cancel)
 791					getToolkit().beep();
 792				return false;
 793			}
 794
 795			find.addCurrentToHistory();
 796			SearchAndReplace.setSearchString(find.getText());
 797
 798			return true;
 799		}
 800		finally
 801		{
 802			saving = false;
 803		}
 804	} //}}}
 805
 806	//{{{ synchronizeMultiFileSettings() method
 807	private void synchronizeMultiFileSettings()
 808	{
 809		directory.setText(view.getBuffer().getDirectory());
 810
 811		SearchFileSet fileset = SearchAndReplace.getSearchFileSet();
 812
 813		if(fileset instanceof AllBufferSet)
 814		{
 815			filter.setText(((AllBufferSet)fileset)
 816				.getFileFilter());
 817		}
 818		else
 819		{
 820			filter.setText("*" + MiscUtilities
 821				.getFileExtension(view.getBuffer()
 822				.getName()));
 823		}
 824	} //}}}
 825
 826	//{{{ closeOrKeepDialog() method
 827	private void closeOrKeepDialog()
 828	{
 829		if(keepDialog.isSelected())
 830		{
 831			// Windows bug workaround in case a YES/NO confirm
 832			// was shown
 833
 834			// ... but if HyperSearch results window is floating,
 835			// the workaround causes problems!
 836			if(!hyperSearch.isSelected())
 837			{
 838				toFront();
 839				requestFocus();
 840				find.requestFocus();
 841			}
 842			return;
 843		}
 844		else
 845		{
 846			GUIUtilities.saveGeometry(this,"search");
 847			setVisible(false);
 848		}
 849	} //}}}
 850
 851	//{{{ load() method
 852	private void load()
 853	{
 854		ignoreCase.setSelected(SearchAndReplace.getIgnoreCase());
 855		regexp.setSelected(SearchAndReplace.getRegexp());
 856		wrap.setSelected(SearchAndReplace.getAutoWrapAround());
 857
 858		if(SearchAndReplace.getReverseSearch())
 859			searchBack.setSelected(true);
 860		else
 861			searchForward.setSelected(true);
 862
 863		if(SearchAndReplace.getBeanShellReplace())
 864		{
 865			replace.setModel("replace.script");
 866			beanShellReplace.setSelected(true);
 867		}
 868		else
 869		{
 870			replace.setModel("replace");
 871			stringReplace.setSelected(true);
 872		}
 873
 874		SearchFileSet fileset = SearchAndReplace.getSearchFileSet();
 875
 876		HistoryModel model = filter.getModel();
 877		if(model.getSize() != 0)
 878			filter.setText(model.getItem(0));
 879		else
 880		{
 881			filter.setText("*" + MiscUtilities
 882				.getFileExtension(view.getBuffer()
 883				.getName()));
 884		}
 885		model = directory.getModel();
 886		if(model.getSize() != 0)
 887			directory.setText(model.getItem(0));
 888		else
 889			directory.setText(view.getBuffer().getDirectory());
 890
 891		searchSubDirectories.setSelected(jEdit.getBooleanProperty(
 892			"search.subdirs.toggle"));
 893
 894		if(fileset instanceof DirectoryListSet)
 895		{
 896			filter.setText(((DirectoryListSet)fileset)
 897				.getFileFilter());
 898			directory.setText(((DirectoryListSet)fileset)
 899				.getDirectory());
 900			searchSubDirectories.setSelected(((DirectoryListSet)fileset)
 901				.isRecursive());
 902		}
 903		else if(fileset instanceof AllBufferSet)
 904		{
 905			filter.setText(((AllBufferSet)fileset)
 906				.getFileFilter());
 907		}
 908
 909		directory.addCurrentToHistory();
 910
 911		keepDialog.setSelected(jEdit.getBooleanProperty(
 912			"search.keepDialog.toggle"));
 913	} //}}}
 914
 915	//}}}
 916
 917	//{{{ Inner classes
 918
 919	//{{{ MyJRadioButton class
 920
 921	// used for the stringReplace and beanShell replace radio buttons,
 922	// so that the user can press tab to go from the find field to the
 923	// replace field in one go
 924	class MyJRadioButton extends JRadioButton
 925	{
 926		MyJRadioButton(String label)
 927		{
 928			super(label);
 929		}
 930
 931		public boolean isFocusTraversable()
 932		{
 933			return false;
 934		}
 935	} //}}}
 936
 937	//{{{ ReplaceActionHandler class
 938	class ReplaceActionHandler implements ActionListener
 939	{
 940		public void actionPerformed(ActionEvent evt)
 941		{
 942			replace.setModel(beanShellReplace.isSelected()
 943				? "replace.script"
 944				: "replace");
 945			SearchAndReplace.setBeanShellReplace(
 946				beanShellReplace.isSelected());
 947		}
 948	} //}}}
 949
 950	//{{{ SettingsActionHandler class
 951	class SettingsActionHandler implements ActionListener
 952	{
 953		public void actionPerformed(ActionEvent evt)
 954		{
 955			Object source = evt.getSource();
 956
 957			if(source == searchCurrentBuffer)
 958				hyperSearch.setSelected(false);
 959			else if(source == searchSelection
 960				|| source == searchAllBuffers
 961				|| source == searchDirectory)
 962				hyperSearch.setSelected(true);
 963
 964			save(true);
 965			updateEnabled();
 966		}
 967	} //}}}
 968
 969	//{{{ MultiFileActionHandler class
 970	class MultiFileActionHandler implements ActionListener
 971	{
 972		public void actionPerformed(ActionEvent evt)
 973		{
 974			if(evt.getSource() == choose)
 975			{
 976				String[] dirs = GUIUtilities.showVFSFileDialog(
 977					view,directory.getText(),
 978					VFSBrowser.CHOOSE_DIRECTORY_DIALOG,
 979					false);
 980				if(dirs != null)
 981					directory.setText(dirs[0]);
 982			}
 983			else if(evt.getSource() == synchronize)
 984			{
 985				synchronizeMultiFileSettings();
 986			}
 987			else // source is directory or filter field
 988			{
 989				// just as if Enter was pressed in another
 990				// text field
 991				ok();
 992			}
 993		}
 994	} //}}}
 995
 996	//{{{ ButtonActionHandler class
 997	class ButtonActionHandler implements ActionListener
 998	{
 999		public void actionPerformed(ActionEvent evt)
1000		{
1001			Object source = evt.getSource();
1002
1003			if(source == closeBtn)
1004				cancel();
1005			else if(source == findBtn || source == find
1006				|| source == replace)
1007			{
1008				ok();
1009			}
1010			else if(source == replaceAndFindBtn)
1011			{
1012				save(false);
1013				if(SearchAndReplace.replace(view))
1014					ok();
1015				else
1016					getToolkit().beep();
1017			}
1018			else if(source == replaceAllBtn)
1019			{
1020				if(searchSelection.isSelected() &&
1021					view.getTextArea().getSelectionCount()
1022					== 0)
1023				{
1024					GUIUtilities.error(view,"search-no-selection",null);
1025					return;
1026				}
1027
1028				setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1029
1030				if(!save(false))
1031				{
1032					setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1033					getToolkit().beep();
1034					return;
1035				}
1036
1037				if(searchSelection.isSelected())
1038				{
1039					if(SearchAndReplace.replace(view))
1040						closeOrKeepDialog();
1041					else
1042						getToolkit().beep();
1043				}
1044				else
1045				{
1046					if(SearchAndReplace.replaceAll(view))
1047						closeOrKeepDialog();
1048					else
1049						getToolkit().beep();
1050				}
1051
1052				setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1053			}
1054		}
1055	} //}}}
1056
1057	//}}}
1058}