Для навигация по иерархии файловых объектов используется дерево папок, что не всегда удобон, а при "свернутой" панели дерева становится невозможным. Для решения данной проблемы создадим альтернативные способы навигации.
Для навигации по дочерним папкам в проводнике можно использовать дерево папок, но при этом, если в созданной нами панели проводника дерево папок будет находиться в “свернутом” состоянии, то получить доступ к дочерним папкам будет невозможно. В аналогичных программных продуктах, например в Windows Explorer, данную операцию можно выполнить либо по нажатию некоторой кнопки (для платформы Windows это обычно кнопка “Enter”), либо двойным щелчком (кликом) мыши.
Для обработки двойного щелчка создаем слушатель с типовым адаптером двойного щелчка мыши.
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; } }
Для дерева папок оставим принятую по умолчанию навигацию по дереву при помощи “стрелок”, а для нажатия клавиши в таблице создаем слушатель с типовым адаптером. Для того чтобы не дублировать код обработчика смены фокуса на дочернюю папку, вынесем данный блок кода в отдельный метод 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(); } . . .
Использование жестко прошитого кода кнопки в данном случае не совсем корректно, в последующем заменим его на константу кода принятой для текущей операционной системы кнопки выбора.
При свернутом дереве проводника переход в “родительскую” папку становится невозможен. Для решения этой задачи обычно применяют либо дополнительную кнопку, либо вводится виртуальная папка, которая предназначена для перехода на вышестоящий уровень в иерархии файловой системы.
Второй способ более удобен, так как позволяет легко перемещаться по ресурсам файловой системы, как с помощью клавиатуры, так и с помощью двойного щелчка (клика) мыши.
Создадим объект-контейнер, который будет содержать информацию о “родительской” папке. Это стандартный 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); . . . } . . .