/**
   * Finds the next occurrence of the search string.
   *
   * @param view The view
   * @return True if the operation was successful, false otherwise
   */
  public static boolean find(View view) {
    // component that will parent any dialog boxes
    Component comp = SearchDialog.getSearchDialog(view);
    if (comp == null || !comp.isShowing()) comp = view;

    String path = fileset.getNextFile(view, null);
    if (path == null) {
      GUIUtilities.error(comp, "empty-fileset", null);
      return false;
    }

    try {
      view.showWaitCursor();

      SearchMatcher matcher = getSearchMatcher();
      if (matcher == null) {
        view.getToolkit().beep();
        return false;
      }

      record(view, "find(view)", false, true);

      boolean repeat = false;
      loop:
      for (; ; ) {
        while (path != null) {
          Buffer buffer = jEdit.openTemporary(view, null, path, false);

          /* this is stupid and misleading.
           * but 'path' is not used anywhere except
           * the above line, and if this is done
           * after the 'continue', then we will
           * either hang, or be forced to duplicate
           * it inside the buffer == null, or add
           * a 'finally' clause. you decide which one's
           * worse. */
          if (reverse) {
            path = fileset.getPrevFile(view, path);
          } else {
            path = fileset.getNextFile(view, path);
          }

          if (buffer == null) continue loop;

          // Wait for the buffer to load
          if (!buffer.isLoaded()) VFSManager.waitForRequests();

          int start;

          if (view.getBuffer() == buffer && !repeat) {
            JEditTextArea textArea = view.getTextArea();
            Selection s = textArea.getSelectionAtOffset(textArea.getCaretPosition());
            if (s == null) start = textArea.getCaretPosition();
            else if (reverse) start = s.getStart();
            else start = s.getEnd();
          } else if (reverse) start = buffer.getLength();
          else start = 0;

          if (find(view, buffer, start, repeat, reverse)) return true;
        }

        if (repeat) {
          if (!BeanShell.isScriptRunning()) {
            view.getStatus().setMessageAndClear(jEdit.getProperty("view.status.search-not-found"));

            view.getToolkit().beep();
          }
          return false;
        }

        boolean restart;

        // if auto wrap is on, always restart search.
        // if auto wrap is off, and we're called from
        // a macro, stop search. If we're called
        // interactively, ask the user what to do.
        if (wrap) {
          if (!BeanShell.isScriptRunning()) {
            view.getStatus().setMessageAndClear(jEdit.getProperty("view.status.auto-wrap"));
            // beep if beep property set
            if (jEdit.getBooleanProperty("search.beepOnSearchAutoWrap")) {
              view.getToolkit().beep();
            }
          }
          restart = true;
        } else if (BeanShell.isScriptRunning()) {
          restart = false;
        } else {
          Integer[] args = {Integer.valueOf(reverse ? 1 : 0)};
          int result =
              GUIUtilities.confirm(
                  comp,
                  "keepsearching",
                  args,
                  JOptionPane.YES_NO_OPTION,
                  JOptionPane.QUESTION_MESSAGE);
          restart = (result == JOptionPane.YES_OPTION);
        }

        if (restart) {
          // start search from beginning
          path = fileset.getFirstFile(view);
          repeat = true;
        } else break loop;
      }
    } catch (Exception e) {
      handleError(comp, e);
    } finally {
      view.hideWaitCursor();
    }

    return false;
  } // }}}
  /**
   * Replaces all occurrences of the search string with the replacement string.
   *
   * @param view The view
   * @param dontOpenChangedFiles Whether to open changed files or to autosave them quietly
   * @return the number of modified files
   */
  public static boolean replaceAll(View view, boolean dontOpenChangedFiles) {
    // component that will parent any dialog boxes
    Component comp = SearchDialog.getSearchDialog(view);
    if (comp == null) comp = view;

    if (fileset.getFileCount(view) == 0) {
      GUIUtilities.error(comp, "empty-fileset", null);
      return false;
    }

    record(view, "replaceAll(view)", true, true);

    view.showWaitCursor();

    boolean smartCaseReplace = getSmartCaseReplace();

    int fileCount = 0;
    int occurCount = 0;
    try {
      SearchMatcher matcher = getSearchMatcher();
      if (matcher == null) return false;

      initReplace();

      String path = fileset.getFirstFile(view);
      loop:
      while (path != null) {
        Buffer buffer = jEdit.openTemporary(view, null, path, false);

        /* this is stupid and misleading.
         * but 'path' is not used anywhere except
         * the above line, and if this is done
         * after the 'continue', then we will
         * either hang, or be forced to duplicate
         * it inside the buffer == null, or add
         * a 'finally' clause. you decide which one's
         * worse. */
        path = fileset.getNextFile(view, path);

        if (buffer == null) continue loop;

        // Wait for buffer to finish loading
        if (buffer.isPerformingIO()) VFSManager.waitForRequests();

        if (!buffer.isEditable()) continue loop;

        // Leave buffer in a consistent state if
        // an error occurs
        int retVal = 0;

        try {
          buffer.beginCompoundEdit();
          retVal = _replace(view, buffer, matcher, 0, buffer.getLength(), smartCaseReplace);
        } finally {
          buffer.endCompoundEdit();
        }

        if (retVal != 0) {
          fileCount++;
          occurCount += retVal;
          if (dontOpenChangedFiles) {
            buffer.save(null, null);
          } else {
            jEdit.commitTemporary(buffer);
            jEdit.getBufferSetManager().addBuffer(view, buffer);
          }
        }
      }
    } catch (Exception e) {
      handleError(comp, e);
    } finally {
      view.hideWaitCursor();
    }

    /* Don't do this when playing a macro, cos it's annoying */
    if (!BeanShell.isScriptRunning()) {
      Object[] args = {Integer.valueOf(occurCount), Integer.valueOf(fileCount)};
      view.getStatus().setMessageAndClear(jEdit.getProperty("view.status.replace-all", args));
      if (occurCount == 0) view.getToolkit().beep();
    }

    return (fileCount != 0);
  } // }}}
  /** Constructor. Sets up and shows the GUI */
  public TextToolsSortDialog(View view, JEditTextArea textArea) {
    super(view, jEdit.getProperty("text-tools.sortadvanced.label"), false);

    this.view = view;
    this.textArea = textArea;
    //		this.data = data;
    //		this.selection = selection;

    view.showWaitCursor();

    sortTableModel = new SortTableModel();

    // preset sortTable if there is a rect selection
    boolean rectSel = false;
    int[] selRows = TextToolsSorting.getRectSelectionRows(textArea);
    if (selRows != null) {
      // we have rectangular selection: assign values to 1st row of table
      sortTableModel.setValueAt(new Integer(selRows[0] + 1), 0, 0);
      sortTableModel.setValueAt(new Integer(selRows[1] + 1), 0, 1);
      rectSel = true;
    }

    sortTable = new JTable(sortTableModel);
    TableColumnModel cMod = sortTable.getColumnModel();
    sortTable.setTableHeader((new SortTableHeader(cMod)));
    sortTable.setRowHeight(25);

    sortTable.setPreferredScrollableViewportSize(new Dimension(430, 200));

    JScrollPane scroll = new JScrollPane(sortTable);

    JPanel content = new JPanel(new BorderLayout());
    content.setBorder(new EmptyBorder(5, 8, 8, 8));
    content.setLayout(new BorderLayout());
    setContentPane(content);
    content.add(scroll, BorderLayout.CENTER);

    JPanel buttons = new JPanel();
    buttons.setBorder(new EmptyBorder(12, 0, 0, 0));
    buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
    buttons.add(Box.createGlue());

    ok = new JButton(jEdit.getProperty("common.ok"));
    ok.addActionListener(this);
    buttons.add(ok);
    buttons.add(Box.createHorizontalStrut(6));
    getRootPane().setDefaultButton(ok);

    cancel = new JButton(jEdit.getProperty("common.cancel"));
    cancel.addActionListener(this);
    buttons.add(cancel);
    buttons.add(Box.createHorizontalStrut(6));

    clear = new JButton("Clear");
    clear.addActionListener(this);
    buttons.add(clear);
    buttons.add(Box.createHorizontalStrut(6));

    help = new JButton("Help");
    help.addActionListener(this);
    buttons.add(help);
    buttons.add(Box.createHorizontalStrut(6));

    buttons.add(Box.createGlue());

    content.add(buttons, BorderLayout.SOUTH);

    delDupsCheckBox =
        new JCheckBox(jEdit.getProperty("text-tools.sortadvanced.delete-identic-lines"));
    onlySelectionCheckBox =
        new JCheckBox(jEdit.getProperty("text-tools.sortadvanced.sort-only-selection"));

    /*
    dontSortCheckBox = new JCheckBox(
    	jEdit.getProperty("text-tools.sortadvanced.dont-sort"));
    delDupsCheckBox.addActionListener(new java.awt.event.ActionListener() {
    	public void actionPerformed(ActionEvent e) {
    		dontSortCheckBox.setEnabled(delDupsCheckBox.isSelected());
    		dontSortCheckBox.setSelected(false);
    	}
    });
    dontSortCheckBox.setEnabled(false);
    */
    JPanel checkBoxes = new JPanel();
    if (rectSel) checkBoxes.add(onlySelectionCheckBox);
    checkBoxes.add(delDupsCheckBox);
    // checkBoxes.add(dontSortCheckBox);  not used, this is an extra action
    content.add(checkBoxes, BorderLayout.NORTH);
    view.hideWaitCursor();
    pack();
    GUIUtilities.loadGeometry(this, "texttools-sort-control");
    setLocationRelativeTo(view);
    setVisible(true);
  } // }}}