BERDAFLEX Software Systems
Главная > Eclipse > Книги > Eclipse RCP. Файловый менеджер

12. Навигация по папкам

ВебвизорДля навигация по иерархии файловых объектов используется дерево папок, что не всегда удобон, а при "свернутой" панели дерева становится невозможным. Для решения данной проблемы создадим альтернативные способы навигации.

12.1. Навигация по “дочерним” папкам

Для навигации по дочерним папкам в проводнике можно использовать дерево папок, но при этом, если в созданной нами панели проводника дерево папок будет находиться в “свернутом” состоянии, то получить доступ к дочерним папкам будет невозможно. В аналогичных программных продуктах, например в Windows Explorer, данную операцию можно выполнить либо по нажатию некоторой кнопки (для платформы Windows это обычно кнопка “Enter”), либо двойным щелчком (кликом) мыши.

12.1.1. Обработка двойного щелчка (клика) мыши

Для обработки двойного щелчка создаем слушатель с типовым адаптером двойного щелчка мыши.

public class ExplorerView extends ViewPart {
. . .
private void initialize() {
. . .
vfsExplorerComposite.getTableViewer().getTable().addMouseListener(
  new org.eclipse.swt.events.MouseAdapter() {
   public void mouseDoubleClick(
    org.eclipse.swt.events.MouseEvent e) {
     StructuredSelection itemSelection = (StructuredSelection) vfsExplorerComposite.getTableViewer().getSelection();
    if ((!itemSelection.isEmpty()) && (itemSelection.getFirstElement() instanceof FileObject)) {
     try {
      setInput(itemSelection.getFirstElement());
      vfsExplorerComposite.getTreeViewer().setSelection(new StructuredSelection(itemSelection.getFirstElement()),	true);
. . .

Данный блок кода “слушает” нажатия мыши и по двойному щелчку проверяется выделенный в данный момент элемент таблицы. Если это элемент типа папка, то производится назначение нового опорного элемента панели методом setInput(..), в качестве которого выступает первый дочерний элемент для выбранной в данный момент папки.

Для единообразия поведения элементов интерфейса пользователя данную функциональность можно добавить и для дерева папок. Но при этом переход на дочернюю папку осуществляем только при наличии дочерних элементов типа “папка”. Для этого в списке дочерних элементов ищем первый элемент указанного типа (теоретически это должен быть самый первый элемент, но нет гарантии, что в будущем логика не поменяется, так что лучше дополнительно проверить).

. . .
vfsExplorerComposite.getTreeViewer().getTree().addMouseListener(
  new org.eclipse.swt.events.MouseAdapter() {
   public void mouseDoubleClick(
    org.eclipse.swt.events.MouseEvent e) {
     StructuredSelection itemSelection = (StructuredSelection) vfsExplorerComposite.getTreeViewer().getSelection();
     if ((!itemSelection.isEmpty()) && (itemSelection.getFirstElement() instanceof FileObject)) {
      FileObject selectedFileObject = (FileObject) itemSelection.getFirstElement();
      try {
       FileObject[] childs = selectedFileObject.getChildren();
       for (int i = 0; i < childs.length; i++) {
        if (childs[i].getType().equals(FileType.FOLDER)) {
         vfsExplorerComposite.getTreeViewer().setSelection(new StructuredSelection(childs[i]),true);
         break;
       }
      }

12.1.2. Навигация по папкам при помощи клавиатуры

Для дерева папок оставим принятую по умолчанию навигацию по дереву при помощи “стрелок”, а для нажатия клавиши в таблице создаем слушатель с типовым адаптером. Для того чтобы не дублировать код обработчика смены фокуса на дочернюю папку, вынесем данный блок кода в отдельный метод selectChildTableFolder(). Останется только проверить код нажатой клавиши на соответствие коду клавиши “Enter” и вызвать созданный метод для перехода в дочернюю папку.

vfsExplorerComposite.getTableViewer().getTable().addKeyListener(
 new org.eclipse.swt.events.KeyAdapter() {
 public void keyPressed(org.eclipse.swt.events.KeyEvent e) {
 if (e.keyCode == 13) {
   selectChildTableFolder();
 }
. . .

Использование жестко прошитого кода кнопки в данном случае не совсем корректно, в последующем заменим его на константу кода принятой для текущей операционной системы кнопки выбора.

12.2. Навигация по “родительским” папкам

При свернутом дереве проводника переход в “родительскую” папку становится невозможен. Для решения этой задачи обычно применяют либо дополнительную кнопку, либо вводится виртуальная папка, которая предназначена для перехода на вышестоящий уровень в иерархии файловой системы.

Второй способ более удобен, так как позволяет легко перемещаться по ресурсам файловой системы, как с помощью клавиатуры, так и с помощью двойного щелчка (клика) мыши.

Рисунок 4.35. Рис. 1. Виртуальная папка для перехода в “родительский” каталог


Создадим объект-контейнер, который будет содержать информацию о “родительской” папке. Это стандартный java бин с доступом к “родительскому” файловому объекту посредством get метода. Особенность реализации заключается в скрытии стандартного конструктора и его переопределении, для единственно возможного способа инициализации.

public class ToParentFolder {

  FileObject parentFileObject;

  private ToParentFolder() {
    super();
  }

  public ToParentFolder(FileObject parentFileObject) {
    super();
    this.parentFileObject = parentFileObject;
  }

  public FileObject getParentFileObject() {
    return parentFileObject;
  }
}

Изменим реализацию провайдера контента для панели списка файловых объектов. Метод получения списка “дочерних” элементов будет теперь добавлять первым элементом массива дополнительный экземпляр класса ToParentFolder, который будет содержать информацию о “родительском файловом объекте. Дополнительно делается проверка на root элемент иерархии объектов, так как доступа к “родительскому” объекту в этом случае нет.

public class VfsTableContentProvider implements IStructuredContentProvider {

  private Object[] getChildren(Object parentElement) {
    if (parentElement instanceof FileObject) {
      try {
        FileObject fileObject = (FileObject) parentElement;
        Object[] kids = null;
        if (fileObject.getType().hasChildren()) {
          kids = fileObject.getChildren();
        }
        if (kids == null) {
          kids = new Object[0];
        }
        if (kids.length > 0) {
          if (((FileObject) parentElement).getParent() != null) {
            int newSize = kids.length + 1;

            Object[] newArray = new Object[newSize];
            newArray[0] = new ToParentFolder((FileObject) parentElement);

            for (int i = 1; i < newSize; i++) {
              newArray[i] = kids[i - 1];
            }

            return newArray;
        } else {
          return kids;
        }
      } else {
        return new Object[] { new ToParentFolder((FileObject) parentElement) };
      }
     } catch (FileSystemException e) {
     . . .
     }
    }
    return new Object[0];
  }
  . . .
}

Теперь очередь за формированием отображения созданной ранее виртуальной папки. Для этого в провайдере меток меняем реализацию получения иконки и текстовой метки. Иконку на данном этапе будем выводить такую же, как и у остальных папок, а в наименование добавим префикс “..”, который обычно используется в командах перехода на вышестоящий уровень иерархии объектов файловой системы. Код провайдера примет вид:

public class VfsTableLabelProvider implements ITableLabelProvider {
  . . .
  public Image getColumnImage(Object element, int columnIndex) {
    . . .
    if ((columnIndex == 0) && (element != null)
      && (element instanceof ToParentFolder)
      && (((ToParentFolder) element).getParentFileObject() != null)) {
      try {
        if ((((ToParentFolder) element).getParentFileObject())
            .getType().equals(FileType.FOLDER)) {
          return PlatformUI.getWorkbench().getSharedImages()
            .getImage(ISharedImages.IMG_OBJ_FOLDER);
      }
     } catch (FileSystemException e) {
     }
    }
    return null;
  }
  . . .
  public String getColumnText(Object element, int columnIndex) {
    if ((element != null) && (element instanceof ToParentFolder)) {
      if (columnIndex == 0) {
        if (((ToParentFolder) element).getParentFileObject() != null) {
          return new StringBuilder("../").append(
            getFileObjectName(((ToParentFolder) element)
            .getParentFileObject())).toString();
        }
    . . .
  }
  . . .
}

Осталось добавить в обработчик нажатий клавиш и кликов мыши панели файлового менеджера поддержку созданного типа данных (класса ).

public class ExplorerView extends ViewPart {
  . . .
  private void selectTableFolder() {
  . . .
if (itemSelection.getFirstElement() instanceof ToParentFolder) {
  try {
    setInput(((ToParentFolder) (itemSelection.getFirstElement()))
      .getParentFileObject().getParent());
    vfsExplorerComposite.getTreeViewer()
      .setSelection(
new StructuredSelection(
((ToParentFolder) (itemSelection.getFirstElement()))
      .getParentFileObject()
      .getParent()), true);
  . . .
  }
 . . .