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