Файловый менеджер
Задание на курсовую работу:
Разработка файлового менеджера. (Аналог Far Manager, Total Commander и т.п.).
Оглавление
Задание на курсовую работу
Введение
1. Аналитическая часть
2. Теоритическая часть
2.1 Глобальные переменные
2.2 Пользовательские функции
3. Конструкторская часть
3.1 Дополнительные возможности
3.1.1 Копирование/перемещение перетаскиванием
3.1.2 Работа с дискетами и дисками
3.1.3 Свойства файлов, папок и дисков
4. Техническая документация
5. Экспериментальная часть
Вывод
Список использованной литературы
Введение
Ни одна операционная система на сегодняшний день не может обойтись без удобного и надежного файлового менеджера. Огромное количество нарастающих с каждым днем данных нуждается в грамотной структуризации и разделении. Не зря все современные операционные системы, как правило, включают в свой состав, в первую очередь, именно файловый менеджер, как неотъемлемую часть самой ОС и необходимый компонент для реализации всех возможностей по доступу к файловой системе. При этом такой доступ должен удовлетворять многим, зачастую противоположным условиям, к которым относятся: возможность быстрого поиска и отображения нужной информации, полнота операций над этими данными, гарантированное исключение ошибок при этих операциях, простота и т.д.
Наличие файлового менеджера в самих ОС не останавливает пользователей в поисках программы «для себя». В данной программе сделана попытка объединить только самые нужные для пользователя функции по работе с файловой системой в наглядном и простом виде. Включение всех возможных операций не было главной целью автора программы, основная задача – необходимый минимум в сочетании с простотой. Программа реализует в себе все способы взаимодействия с пользователем и другими программами, предоставляемые операционной средой Windows, как то: работа с буфером Clipboard, перемещение и копирование посредством перетаскивания (Drag’n’Drop), контекстные меню, панель управления и др.
Данный файловый менеджер не претендует на звание самого удобного или самого полного, а лишь отражает взгляд автора на то, каким должен быть простой, но вместе с тем функциональный проводник по файловой системе. Доступ к информации о системе полностью осуществляется через API Windows, что делает программу легко переносимой среди ОС этого класса. Программа написана в среде Microsoft Visual Studio 2008.
1. Аналитическая часть
Основной концепцией стало сосредоточение максимума информации в одном окне таким образом, чтобы обеспечить простой и быстрый переход по иерархической файловой системе. Для этого главное окно программы было разбито мысленно на 4 части: иерархическое окно папок, последовательный список файлов, управляющие меню и панель и окно информации (панель состояния). Все эти компоненты безусловно связаны между собой и выполняют общую задачу – наиболее полное отображение информации.
Дерево папок представляет собой объект класса TTreeView, в который программным образом загружается иерархическая файловая структура носителей информации ПК. Данный компонент должен обеспечить быстрый доступ к отдельным контейнерам (папкам, директориям, дискам) файловой системы, корнем дерева служит виртуальный компонент «Мой компьютер», замыкающий на себе все диски. Список файлов представлен объектом класса TListView и содержит список содержимого, активизированной в данный момент в дереве директории. При этом связь между списком и деревом не только прямая, но и обратная – открытие вложенных папок в списке влечет за собой последовательное раскрытие дерева. Список содержит довольно полную информацию о файле (вложенной директории), начиная с имени и заканчивая датой создания. Дерево и список взаимодействуют между собой и в процессе обмена файлами посредством перетаскивания. Перетаскивание может осуществляться как в пределах одного компонента (папки в папку в TreeView, файла в папку в ListView), так и между компонентами.
Меню (класс TMainMenu) и панель управления (класс TControlBar) реализуют набор операций над элементами файловой системы: создание папки, копирование, удаление, вырезание и т.д. А, кроме того, позволяют изменять само отображение этих элементов, а также порядок их сортировки, что в некоторых случаях бывает крайне полезно. Важным свойством элементов управления является их интерактивность – те команды, которые в текущих обстоятельствах не могут быть выполнены, скрываются или отображаются в элементах блеклым цветом. К компонентам управления следует отнести и контекстное меню, подменяющее пункты главного и позволяющее не отвлекаться от списка и дерева путем обращения к нему нажатием правой клавиши.
Наконец информационная панель (панель состояния, статуса) (класс TStatusBar) жестко связана со списком файлов и отображает количество элементов, а также свободное место на диске.
Итак, все компоненты хотя и графически разделены, но логически связаны между собой в любой момент времени, что позволяет пользователю не отвлекаться от главной задачи – доступа к некоторому элементу файловой системы и выполнения операции над ним. Именно поэтому была выбрана такая структура программы (панель папок – панель файлов) в противовес организации двух списков файлов в стиле Norton Commander, ведь работа с одной из панелей полностью автономна по отношению к другой. Доступ к глубоко лежащим в структуре объектам в такой системе, по мнению автора неудобна, в отличие от использования панели папок, которая позволяет за несколько щелчков добраться до любого контейнера. К тому же именно структура «папки – список» позволяет логично организовать работу с объектами в стиле Drag’n’Drop.
2. Теоритическая часть
Все операции при реализации программы были сознательно вынесены из обработчиков событий в отдельные функции-члены класса, для удобства их вызова из любых мест программы и большей структурированности кода. Поэтому большее внимание при описании реализации будет уделено именно таким функция, а не обработчикам событий, которые лишь содержат их вызовы.
2.1 Глобальные переменные
Код программы содержит ряд глобальных переменных, хранящих информацию о состоянии ее выполнения: виде отображения значков, вставленных дисках, отсортированной колонке и т.д.
Данные об установленных жестких дисках и приводов дискет хранят 2 переменные - set_drive_num и DiskIn, причем первая содержит номера присутствующих приводов, вторая же имена тех из них, в которые вставлена дискета или оптических диск, что позволяет динамически отслеживать пустые приводы и запрещать обращение к ним.
Ряд переменных хранит информацию о состоянии списка файлов и папок ListView1: CurrentDir – название текущего каталога, StyleListView – стиль отображения значков (список, таблица…), ColumnToSort – номер сортируемой колонки, Direct – направление сортировки (прямое, обратное).
Переменная type_file_operation_drag_drop указывает на необходимость копирования или переноса файла при перетаскивании, что определяется по нажатию соответствующих функциональных клавиш, а установкой DragnDrop в ложь можно вовсе запретить всякие операции посредством переноса.
Пользовательские функции
Вспомогательные функции: void FirstUpOtherDown(char) и void FirstUpOtherDown(AnsiString).
Осуществляют изменение регистра букв переданных в качестве параметра строк таким образом, чтобы все символы имели нижний регистр, кроме первого символа. Используются при добавлении элементов в список и дерево для выравнивания букв в названии файлов, папок.
Функции поиска и отображения, содержащихся в системе носителей данных и приводов: void GetDrives() и void ShowDrives().
Функция GetDrives осуществляет первичный поиск носителей и осуществляет загрузку их номеров в глобальную переменную. Само отображение выполняется в ShowDrives, где помимо анализа полученной информации осуществляется построение названия диска, исходя из его номера и имени метки. Определение типа привода позволяет загрузить соответствующее изображение, а точнее выбрать его из списка изображений ImageList.
Функции добавления элементов (записей, узлов) в дерево и список файлов: TTreeNode* AddChildInNodeTree(TTreeNode, AnsiString), TListItem *AddItemInListView (TSearchRec, AnsiString).
Функция добавления записи в дерево осуществляет вставку потомка для переданного в функцию узла. Осуществляется настройка свойств вставляемого элемента: пути к нему (свойство Data), значка (свойство ImageIndex и SelectedIndex), имени (свойство Name).
Функция добавления записи в список извлекает из переданной структуры TSearchRec необходимые элементы – дату, название, а также сама осуществляет поиск дополнительной информации API функцией SHGetFileInfo – название типа и значок, соответствующий типу файла. В итоге функция осуществляет полное формирование строки и возвращает указатель на нее.
Функции формирования дерева: void ViewChild(TTreeNode *), void DeleteChild(TTreeNode* Node) и вспомогательная функция bool CheckExpandedChild(TTreeNode *).
Основная идея формирования дерева – нет необходимости в полном его построении в начале выполнения программы, что, безусловно, сокращает время на запуск и уничтожает необходимость в обходе всех папок на диске. В этой ситуации возникает проблема динамического построения дерева во время его раскрытия – свертывания. Реализацией этой идеи и стали функции ViewChild и DeleteChild. Первая принимает в качестве параметра указатель на раскрываемый узел, который использует для обхода всех его потомков (вложенных папок узла) и благодаря которому находит для этих потомков свои вложенные папки. При обходе для этих вложенных папок добавляются соответствующие узлы. Таким образом, в целом функция предназначена для добавления в дерево потомков потомков (внуков) раскрываемых узлов. Это позволяет вовремя добавлять узлы, тем самым, скрывая неполноту дерева. Необходимость наличия при раскрытии узла именно внуков, а не только детей связана с тем, что в раскрытой ветви, составленной из детей, уже должно быть очевидно наличие возможного продолжения раскрытия.
Функция DeleteChild выполняет обратную операцию – удаляет внуков сворачиваемого узла, тем самым предостерегается возможность двукратного дополнения узла в дерево.
Из этих правил есть одно исключение – ситуация, когда среди потомков сворачиваемого узла есть развернутые ветви. Удаление внуков в этом случае приведет к нарушению структуры дерева (развернутые внутри сворачиваемого узла узлы будут свернуты). Проверку такой ситуации осуществляет функция CheckExpandedChild – она возвращает true в случае наличия хотя бы одного развернутого потомка у переданного в качестве параметра узла.
Функция формирования списка файлов и каталогов: void ViewFailAndFolderInListView (AnsiString dir).
Задача функции проста: вывести на экран содержание переданной по параметру папки dir. Порядок ее осуществления: очистка списка, поиск файлов (папок) в указанном каталоге функциями FindFirst, FindNext, FindClose, добавление соответствующих найденным файлам записей вышеописанной функцией AddItemInListView, сохранение текущего каталога, обновление статусной панели информации.
Функция выполнения операций над файлами int FileAndFolderOperation(char *frombuf, char *tobuf, unsigned int operation) и вспомогательная функция формирования строки-списка файлов void PrepareBufForOperationInListView(char * &).
Функция FileAndFolderOperation выполняет простую операцию – согласно полученным данным: символьному массиву «откуда копировать» frombuf и массиву «куда копировать» tobuf, а также коду операции заполняет структуру SHFILEOPSTRUCT и передает ее на обработку API функции SHFileOperation, а также возвращает результат ее выполнения.
Самой сложной частью выполнения операций над файлами является заполнение символьной строки frombuf, особенно для ListView, т.к. позволяется выделение целой группы файлов и папок. Буфер же frombuf должен содержать пути ко всем объектам, разделенные символом ‘\0’ и заканчивающиеся двойным символом нуля. Именно для этого введена процедура PrepareBufForOperationInListView. В данной процедуре осуществляется анализ выделенных объектов в ListView и соответствующее заполнение буфера frombuf. Для этого используется ряд вспомогательных процедур: strcat0 и finstr. Первая соединяет две строки, оставляя между ними символ нуля, вторая финализирует строку – добавляет в конце два символа двойного нуля.
Функции обновления дерева, списка, меток: void UpdateTreeView(bool UpdateAllways), void UpdateListView(bool UpdateAllways), void UpdateLabel(), void UpdateAll(bool UpdateAllways) и вспомогательная функция void RecursTree(TTreeNode *node,bool UpdateAllways).
Обновление дерева каталогов осуществляется двумя функциями – UpdateTreeView и RecursTree. Первая – бутафорская и осуществляет лишь запуск рекурсивной функции RecursTree. Ее основная задача – найти вершину дерева и передать ее в RecursTree.
Функция RecursTree осуществляет подсчет числа папок в переданной ее директории и сравнивает с числом детей, соответствующего директории узла. Несовпадение этих переменных запускает цикл проверки. В случае большего количества узлов-потомков проверяется наличие-отсутствие соответствующих им папок. Отсутствие папки приводит к удалению узла, сопоставленного ей, и всех его потомков. В обратной ситуации, перебираются папки, и выясняется какой из соответствующих им узлов нужно добавить. Рекурсивная функция запускает себя вновь, если текущий узел раскрыт – соответственно начинается обход потомков потомков. Отсутствие раскрытия приводит к рекурсивному возврату.
Обновление списка файлов аналогично и даже проще. Отпадает необходимость использования рекурсивных функций – уровень только один. В функции UpdateListView аналогично осуществляется сравнение количества папок в текущем каталоге с количеством записей, их несоответствие приводит к ряду проверок, описанных выше. Добавляется еще одна проверка на наличие текущего каталога. Его отсутствие означает простую очистку списка и указания текущей пустой папки.
В задачу функции UpdateLabel входит просмотр меток всех приводов и переформирование заголовков дисков дерева в соответствии с найденной информацией.
Объединение всех функций обновления осуществляется процедурой UpdateAll, помимо вызовов вышеперечисленных функций обновляется и панель статуса - пересчитываются элементы списка, переопределяется свободное место на диске.
Во все функции обновления передается в качестве параметра булева переменная UpdateAllways. Установка этой переменной в true означает принудительную проверку списка и дерева даже в том случае, если количество записей совпадает с числом сопоставленных элементов. Это полезно например при переименовании – число записей не меняется, но меняются их имена.
Функция переименования AnsiString RenameFileOrFolder(AnsiString NewName).
Данная функция получает параметром новое имя для находящегося в фокусе объекта. Путем проверки состояния ListView и TreeView и определения находящегося в фокусе узла, определяется текущий объект и путь к нему (по свойству Data). Затем формируются символьные массивы » frombuf, исходя из бывшего пути, и tobuf, по новому имени. Осуществление попытки переименования заканчивается возвратом либо нового имени, в случае ее удачи, либо прежнего, если переименование не удалось. Это полезно в функция редактирования имен узлов – узлу назначается имени, возвращенное функцией.
Функция удаления void DeleteFileOrFolder().
Работа функции довольно проста – необходимо определить какой из элементов в фокусе (ListView или TreeView), заполнить массив frombuf путями, соответствующими выделенным там узлам (согласно свойству узлов Data), передать все это на обработку функции FileAndFolderOperation с указанием операции – FO_DELETE.
Функция создания папки void CreateFol().
Идея построения данной функции такова – создается папка с произвольным именем, но после создания фокус немедленно передается записи, отображающей ее, с указанием редактирования. Тем самым пользователь получает возможность немедленно изменить ее имя на любое другое. Таким образом задействуется вышеописанная функция переименования. Формирование имени папки осуществляется из сочетания «Новая папка» и числа, которое подбирается таким образом, чтобы соответствующая папка отсутствовала в системе.
Служебные функции ListView: void ExpandTreeForFile(AnsiString FileName) и void OpenFileOrFolder().
Функция OpenFileOrFolder вызывается при клике на элементе списка ListView и осуществляет соответствующую операцию: при клике на папке – открывает ее, при клике на файле – запускает его. По щелчку на папке происходит вызов ViewFailAndFolderInListView с указанием пути к ней для отображения содержимого, по щелчку на файле предпринимается попытка запустить его функцией ShellExecute. Если попытка запуска неудачна, на экран выводится сообщение об ошибке, возвращаемое GetLastError.
Вызов функции ExpandTreeForFile осуществляется лишь из процедуры OpenFileOrFolder и предназначен для раскрытия ветвей дерева до текущей папки, при ее изменении. Новая текущая папка передается в функцию в качестве параметра, где этот путь последовательно разбивается на части и сопоставляется различным узлам дерева. Последовательным проходом сверху-вниз осуществляется раскрытие узлов, соответствующих родительским директориям, содержащим данную папку, и выделение новой текущей директории в дереве TreeView. Так становится возможной связь компонента ListView с TreeView: изменение текущей директории в ListView приводит к изменению выделения текущего контейнера в TreeView.
Функции работы с буфером: void PasteFileFromClipboard(), void CopyFileToClipboard(bool Copy).
При включении возможности работы с буфером была поставлена задача полной совместимости формата передаваемых файлов с форматом, используемым файловыми менеджерами Windows, например, «Проводником». Этим форматом является CF_HDROP, предполагающий наличие в буфере указателя на структуру DROPFILES и следующую за ней строку последовательно перечисленных путей к объектам, помещенным в буфер.
Исходя из этого, реализация операции по вставке файлов из буфера была осуществлена в следующем порядке: открытие буфера OpenClipboard, проверка наличия в буфере данных нужного формата функцией IsClipboardFormatAvailable; получение указателя на данные GetClipboardData и, наконец, определение их количества и последовательное извлечение строк API функцией DragQueryFile. На основании полученных строк формируется массив frombuf передаваемый на обработку.
Еще одной проблемой стало получение информации о необходимости копирования, либо перемещения файла. Стандартом является получение указателя из буфера по регистрируемому формату CFSTR_PREFERREDDROPEFFECT. Указатель содержит адрес в памяти, по которому находится четыре байта информации о типе перемещения/копирования. Сравнением этих данных с константами и вызовом функции FileAndFolderOperation и завершается вставка файлов (папок) из буфера. Закрытие буфера по окончании функции разрешает доступ к нему для других программ.
Функция void CopyFileToClipboard(bool Copy) универсальная и в зависимости от переданного ей параметра осуществляет либо копирование, либо перемещение файла в буфер (точнее, лишь указание на перемещение или копирование). Результатом анализа переданного параметра является выделением памяти под двойное слово и помещение в нее соответствующей константы DROPEFFECT_COPY или DROPEFFECT_MOVE. Передача информации о копируемых файлах осуществляется последовательным заполнением структуры DROPFILES, построением буфера frombuf и перемещения этих данных в память. После открывается буфер, функцией SetClipboardData в буфере размещаются данные о фалах и типе операции, буфер закрывается – данные готовы к копированию (перемещению).
3.Конструкторская часть
файловый менеджер система пользовательский
TreeView1 : TTreeView
Данный визуальный объект изображает дерево каталогов и настраивается динамически в процессе работы путем добавления/удаления узлов. Основные события, участвующие в формировании дерева – OnExpanded и OnCollapsing, возникающие соответственно при раскрытии и свертывании некоторого узла. По первому событию осуществляется помещение в дерево внуков раскрываемого узла посредством функции ViewChild, по последнему – удаление внуков сворачиваемого узла процедурой DeleteChild. Пользователь полностью скрыт от информации об изменении структуры дерева.
Обработчик события OnClick обеспечивает реакцию на щелчок на изображении некоторой папки. Задача обработчика – вызов процедуры перерисовки списка файлов в соответствии с изменившемся текущим каталогом.
Сортировка элементов дерева, осуществляется стандартным способом: путем включения условия сравнения в обработчик события OnCompare.
ListView1 : TListView
Визуальный объект имитирует список файлов и каталогов и изменяет свою структуру всякий раз, когда меняется текущая директория. Основное событие, участвующее в формировании - OnDoubleClick. Оно возникает при двойном щелчке на одном из пунктов списка, и в случае если им является папка, обработчик изменяет текущую директорию и вызывает функция переформирования элементов ListView.
Сортировка аналогично TreeView осуществляется вписыванием нужного условия по событию OnCompare. А вот само условие сравнение может меняться и зависит от глобальных переменных ColumnToSort и Direct. Изменение колонки сортировки и направления может происходить как из меню, но чаще путем клика на заголовке столбца. Для этой ситуации предназначен обработчик события – OnColumnClick. Извлекающий данные о новом сортируемом столбце и вызывающий процедуру пересортировки списка – AlphaSort.
Еще одним важным событием для списка файлов менеджера является OnEdited, возникающее по окончанию переименования некоторого элемента. Обработчик предусматривает вызов процедуры переименования файла, которая в случае успеха позволяет переименовать узел, в случае неудачи имя узла остается неизменным.
StatusBar1 : TStatusBar
Этот компонент служит для вывода справочной информации, вывод которой осуществляется в пользовательских функциях: ViewFailAndFolderInListView и UpdateAll.
Элементы управления MainMenu1 : TMainMenu, ControlBar1 : TControlBar и PopupMenu1 : TPopupMenu.
Элементы управления содержат схожие группы команд и позволяют пользователю влиять на работу приложения.
Работа компонента MainMenu организуется обработкой нажатий на отдельные пункты меню, как-то «Создать папку», «Удалить», «Переименовать» и т.д. Обработчики нажатий, как правило, содержат лишь вызов соответствующих процедур. ControlBar1 и PopupMenu1 в основном дублируют пункты меню и содержат аналогичные обработчики. Они введены для удобства пользователя и более быстрому доступу к отдельным командам.
Эти компоненты отличаются лишь способом динамического формирования меню. Для ControlBar1, правда, вообще отсутствуют какие-либо изменения, а вот MainMenu1 и PopupMenu1 меняют состав своих компонентов. Для MainMenu1 осуществляется динамического отслеживание активных компонентов и при открытии группы команд происходит отключение (подсвечивание блеклым светом) тех из них, которые не могут быть доступны в текущий момент. Так как компонент PopupMenu1 представляет собой довольно длинный линейный список команд, закрывающий собой большую часть экрана, ненужные действия просто изымаются из всплывающего меню. Пользователь видит лишь те, которые возможны в текущий момент.
Дополнительные возможности
3.1.1Копирование/перемещение перетаскиванием
Копирование/перемещение осуществляется перетаскиванием между двумя компонентами ListView и TreeView. Для осуществления такой возможности используются 3 события в каждом из компонентов: OnMouseDown, OnDragOver и OnDragDrop (расставлены в порядке использования). Первое из них начинает процесс перетаскивания, а именно: проверяет нажата ли левая клавиша на компоненте, осуществляет распознавание типа перетаскивания (копирование/перемещения) путем анализа нажатия клавиши CTRL, начинает перетаскивание методом BeginDrag.
Событие OnDragOver возникает при каждый раз при перемещении перетаскиваемого элемента по объекту. Здесь необходимо определить возможность получения элемента, путем анализа источника и места помещения в приемнике.
Наступление события OnDragDrop означает окончание перетаскивания. В обработчике анализируются перемещенный элемент и место его опускания. В соответствии с этими данными, а также производимой операцией, сохраненной в глобальной переменной обработчиком OnMouseDown, осуществляется заполнение буферов frombuf и tobuf и вызов FileAndFolderOperation с соответствующим кодом.
Работа с дискетами и дисками
Работа с дискетами и дисками осложнена тем, что отсутствие носителя информации приводит к неоправданному обращению к приводу и появлению различных информационных сообщений на экране, что, безусловно, раздражает пользователя, не работающего с дискетой/диском. Для исключения таких ситуаций для приводов со сменными носителями предусмотрена глобальная переменная DiskIn в виде перечисления. Она включает в себя буквы тех приводов в которые действительно вставлены носители. Проверка таким образом наличия диска/дискеты, необходимая во многих функциях работы с деревом, вроде обновления и т.д, заключается в обращении к этой глобальной переменной. Помещение букв носителей в это множество осуществляется при удачном обращении к приводу со вставленной дискетой/диском. Удаление организуется при первом неудачном обращении к приводу дисков/дискет – имя диска удаляет из множества DiskIn. Результатом введения такой переменной стал запрет доступа к незаполненным приводам.
3.1.3 Свойства файлов, папок и дисков
Важной частью файлового менеджера являются средства отображения свойств различных объектов файловой системы. Реализация этих средств была сведена к созданию двух дополнительных форм FPropertyFile и FPropertyDrive, заполняемых необходимыми данными в процессе получение свойств посредством API Windows. Разделение форм было произведено из-за существенного различия типа информации в свойствах дисков и файлов.
Предварительное заполнение и отображение формы FPropertyFile осуществляется в пользовательской функции Prepare, получающей в качестве параметра путь к файлу. Ниже перечислены основные отображаемые свойства и методы их получения: иконка файла/папки, тип файла (функция SHGetFileInfo); имя файла/папки (функция ExtractFileName); папки (ExtractFilePath); размера (функция GetFileAttributesEx), размера на диске (функции GetFileAttributesEx и GetDiskFreeSpace для получения информации о размере кластера/сектора); даты создания, изменения, открытия (функции GetFileAttributesEx и FileTimeToLocalFileTime, FileTimeToSystemTime и SystemTimeToDateTime для преобразования даты к удобному виду); свойства файла/папки (функция GetFileAttributesEx). Для определения размера папки и количества, содержащихся в ней объектов, используется рекурсивная функция Get_Size_Folder, обходящая всю иерархическую структуру директории, подсчитывая и суммируя размеры отдельных объектов. Сохранение возможно измененных имени и атрибутов осуществляется в процедуре Set_Change.
Аналогично FPropertyFile заполнение полей формы FPropertyDrive производится в процедуре Prepare. Свойства, отображаемые с помощью элементов формы, следующие: иконка (по типу диска функцией GetDriveType); метка диска и тип файловой системы (функция GetVolumeInformation); количество занятого и свободного места (функция GetDiskFreeSpaceEx). Кроме того занятое/свободное место отображается в виде круговой диаграммы – объект класса TChart. Единственным свойством изменение которого возможно является метка диска. Именно она изменяется по нажатию на клавиши OK или «Применить».
Вызов функций отображения и подготовки форм осуществляется из процедуры ViewProperty. Единственная задача этой функции - определить какую из форм следует показать. Эта проблема решается путем сравнения пути к отображаемой папке с путем к корневому каталогу диска.
4. Техническая документация
Приложение не требует установки. Для его работы следует запустить FileManager.exe. Приложение рекомендуется для работы с файловой системой и файлами. Файловый менеджер позволяет выполнять наиболее частые операции над файлами - создание, открытие/проигрывание/просмотр, редактирование, перемещение, переименование, копирование, удаление, изменение атрибутов и свойств, поиск файлов и назначение прав.
5. Экспериментальная часть
При запуске программы создается главная форма, затем приложение ожидает действия пользователя. Каждому предусмотренному действию сопоставлена какая-то функция-обработчик.
При нажатии на кнопки «Удалить» и «Создать» программа выводит на экран соответствующие диалоговые окна, где так же есть предусмотренные действия пользователя с объектами на этих формах.
После выполнения какого-либо действия, программа возвращается в режим ожидания пользовательских действий.
Для завершения работы с Файловым Менеджером пользователю достаточно нажать на кнопку «Закрыть» системного меню, находящуюся в правом верхнем углу окна программы.
Выводы
Результатом данной курсовой работы является программа для работы с файлами. Программа представляет собой необходимый минимум для выполнения этой задачи.
Программа может иметь более развитый интерфейс и двупанельный вид — в общем случае имеют две равноценных панели для списка файлов, а в данном случае программа имеет однопанельный вид. В данной курсовой работе это не было реализовано.
Список используемой литературы
Общая информация
http://yandex.ru/
http://www.google.ru/
http://ru.wikipedia.org/
Информация о языке программирования
http://www.itkursi.ru/
Пауэрс Л., Снелл М. Microsoft Visual Studio 2008 => Microsoft Visual Studio 2008 Unleashed by Lars Powers and Mike Snell.
Алгоритмы программы
http://program.rin.ru/
http://www.progz.ru/
Листинги
Листинг Unit1.h
enum {ImageWindows, ImageFloppy, ImageDrive, ImageCD, ImageMyComp,ImageCloseFolder, ImageOpenFolder};
void strcat0(char * &dest,char *source); //Соединение строк с оставлением нулевого символа
void finstr(char *dest);
unsigned int lengthfinstr(char *dest);
struct DROPFILES {
DWORD pFiles; // offset of file list
POINT pt; // drop point (client coords)
BOOL fNC; // is it on NonClient area
// and pt is in screen coords
BOOL fWide; // WIDE character switch
};
class TForm1 : public TForm
{
__published: // IDE-managed Components
TMainMenu *MainMenu1;
TMenuItem *NFile;
TTreeView *TreeView1;
TSplitter *Splitter1;
TListView *ListView1;
TImageList *ImageList1;
TImageList *ImageList2;
TMenuItem *NProperty;
TImageList *ImageList3;
TImageList *ImageList4;
TControlBar *ControlBar1;
TToolBar *TBMain;
void __fastcall TreeView1Expanding(TObject *Sender,
TTreeNode *Node, bool &AllowExpansion);
void __fastcall TreeView1Compare(TObject *Sender, TTreeNode *Node1,
TTreeNode *Node2, int Data, int &Compare);
void __fastcall TreeView1Expanded(TObject *Sender,
TTreeNode *Node);
void __fastcall TreeView1Collapsing(TObject *Sender,
TTreeNode *Node, bool &AllowCollapse);
void __fastcall TreeView1Editing(TObject *Sender, TTreeNode *Node,
bool &AllowEdit);
void __fastcall ListView1Compare(TObject *Sender, TListItem *Item1,
TListItem *Item2, int Data, int &Compare);
void __fastcall ListView1DblClick(TObject *Sender);
void __fastcall ListView1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y);
void __fastcall TreeView1DragOver(TObject *Sender, TObject *Source,
int X, int Y, TDragState State, bool &Accept);
void __fastcall TreeView1DragDrop(TObject *Sender, TObject *Source,
int X, int Y);
void __fastcall TreeView1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y);
void __fastcall NPropertyClick(TObject *Sender);
void __fastcall NOpenClick(TObject *Sender);
void __fastcall NExitClick(TObject *Sender);
void __fastcall NDeleteClick(TObject *Sender);
void __fastcall TBDeleteClick(TObject *Sender);
void __fastcall TBPropertyClick(TObject *Sender);
void __fastcall TBExitClick(TObject *Sender);
void __fastcall NViewClick(TObject *Sender);
void __fastcall NPanelClick(TObject *Sender);
void __fastcall NStatusBarClick(TObject *Sender);
void __fastcall TBUpClick(TObject *Sender);
void __fastcall TreeView1Edited(TObject *Sender, TTreeNode *Node,
AnsiString &S);
void __fastcall ListView1Edited(TObject *Sender, TListItem *Item,
AnsiString &S);
void __fastcall NRenameClick(TObject *Sender);
void __fastcall TBRenameClick(TObject *Sender);
void __fastcall NIconClick(TObject *Sender);
void __fastcall NSmallIconClick(TObject *Sender);
void __fastcall NListClick(TObject *Sender);
void __fastcall NReportClick(TObject *Sender);
void __fastcall ListView1DragOver(TObject *Sender, TObject *Source,
int X, int Y, TDragState State, bool &Accept);
void __fastcall ListView1DragDrop(TObject *Sender, TObject *Source,
int X, int Y);
void __fastcall TBUpdateClick(TObject *Sender);
void __fastcall TreeView1Click(TObject *Sender);
void __fastcall TBPasteClick(TObject *Sender);
void __fastcall TBCopyClick(TObject *Sender);
void __fastcall TBCutClick(TObject *Sender);
void __fastcall NUpdateClick(TObject *Sender);
void __fastcall NCutClick(TObject *Sender);
void __fastcall NPasteClick(TObject *Sender);
void __fastcall NCopyClick(TObject *Sender);
void __fastcall NSelectAllClick(TObject *Sender);
void __fastcall ListView1ColumnClick(TObject *Sender,
TListColumn *Column);
void __fastcall NSort0Click(TObject *Sender);
void __fastcall NCreateFolderClick(TObject *Sender);
void __fastcall NFileClick(TObject *Sender);
void __fastcall NEditClick(TObject *Sender);
void __fastcall ListView1ContextPopup(TObject *Sender,
TPoint &MousePos, bool &Handled);
void __fastcall TreeView1ContextPopup(TObject *Sender,
TPoint &MousePos, bool &Handled);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
void ShowDrives();
void ViewChild(TTreeNode *child);
void DeleteChild(TTreeNode *Node);
void ViewFailAndFolderInListView(AnsiString dir);
void ExpandTreeForFile(AnsiString FileName);
int FileAndFolderOperation(char *frombuf, char *tobuf, unsigned int operation);
TTreeNode* AddChildInNodeTree(TTreeNode *Node, AnsiString Dir);
TListItem *AddItemInListView(TSearchRec sr,AnsiString dir);
void ViewProperty();
void OpenFileOrFolder(); //Открыть в Listview файл или папку
void DeleteFileOrFolder();
void PrepareBufForOperationInListView(char * &frombuf);
AnsiString RenameFileOrFolder(AnsiString);
void RecursTree(TTreeNode *node,bool); //Рекурсивное обновление дерева
void UpdateTreeView(bool); //Функция запуска рекурсивного обновления дерева
void UpdateListView(bool); //Функция обновления listview
void UpdateAll(bool);
void PasteFileFromClipboard(); //Вставить из буфера
void CopyFileToClipboard(bool); //Копировать файлы в буфер
void CreateFol();
void UpdateLabel();
} ;
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Листинг Unit1.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <shellapi.h>
#include "Unit1.h"
#include <winbase.h>
#include <vector.h>
#include "PropertyFile.h"
#include "PropertyDrive.h"
#include <ole2.h>
#define CFSTR_PREFERREDDROPEFFECT TEXT("Preferred DropEffect")
using namespace std;
vector <int> set_drive_num; //Вектор с номерами установленных дисков
TTreeNode *head, *tpItem; //Голова и темповая переменная
//указатель на верхний отображаемый
//узел для отсутствия скачков
unsigned int type_file_operation_drag_drop;
//Тип операции при drag drop
AnsiString CurrentDir=""; //Текущий каталог
TViewStyle StyleListView=vsReport;
Set<char, 'A', 'Z'> DiskIn;
bool DragnDrop=true; //Флаг разрешения перетаскивания
int ColumnToSort=0; //Номер колонки по которой сортируют
int Direct=1; //Направление соритировки
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
void FirstUpOtherDown(char *str) //Опускает все буквы кроме первой
{
if((str[0]>96 && str[0]<123) || (str[0]>223 && str[0]<255))
str[0]-=32;
for(int i=1;str[i]!='\0';i++)
if((str[i]>64 && str[i]<91) || (str[i]>191 && str[i]<224))
str[i]+=32;
}
void FirstUpOtherDown(AnsiString &str)
{
if((str[1]>96 && str[1]<123) || (str[1]>223 && str[1]<255))
str[1]-=32;
for(int i=2;i<=str.Length();i++)
if((str[i]>64 && str[i]<91) || (str[i]>191 && str[i]<224))
str[i]+=32;
}
void GetDrives() //Определяет установленные диски
{ //и сохраняет их номера в set_drive_num
unsigned int set_drive=GetLogicalDrives();
for(int i=0;set_drive!=0;i++)
{
if(set_drive%2) set_drive_num.push_back(i);
set_drive>>=1;
}
}
void TForm1::ShowDrives() //Отображает диски в дереве
{
char str[10];
char inf[20];
for(unsigned int i=0;i<set_drive_num.size();i++)
{
TTreeNode *temp; //Загрузка узла
str[0]=(char)('A'+set_drive_num[i]);
str[1]='\0';
strcat(str,":\\");
if(set_drive_num[i]!=0 && set_drive_num[i]!=1) //Заполнение информационного поля
{
if(!GetVolumeInformation(str,inf,20,NULL,NULL,NULL,NULL,NULL)) //Получение метки тома
strcpy(inf,"");
}
else
{
strcpy(inf,"");
}
FirstUpOtherDown(inf);
AnsiString *p=new AnsiString(str);
temp=TreeView1->Items->AddChildObject(head,AnsiString(inf)+" ("+(char)('A'+set_drive_num[i])+":)",p);
switch(unsigned int p=GetDriveType(str)) //Загрузка image
{
case DRIVE_REMOVABLE:
temp->SelectedIndex=ImageFloppy;
temp->ImageIndex=ImageFloppy;
break;
case DRIVE_FIXED:
case DRIVE_RAMDISK:
temp->SelectedIndex=ImageDrive;
temp->ImageIndex=ImageDrive;
break;
case DRIVE_CDROM:
temp->SelectedIndex=ImageCD;
temp->ImageIndex=ImageCD;
break;
default:
temp->SelectedIndex=ImageWindows;
temp->ImageIndex=ImageWindows;
break;
}
}
}
TTreeNode* TForm1::AddChildInNodeTree(TTreeNode *Node, AnsiString Dir)
{
AnsiString temp=Dir;
AnsiString Name=ExtractFileName(temp.SetLength(temp.Length()-1));
FirstUpOtherDown(Name);
AnsiString *p=new AnsiString(Dir); //Добавляем новый потомок к treeview
TTreeNode *t=TreeView1->Items->AddChildObject(Node,Name,p);
t->ImageIndex=ImageCloseFolder;
t->SelectedIndex=ImageOpenFolder;
return t; //Возвращаем указатель на него
}
void TForm1::ViewChild(TTreeNode *Node) //Отображение детей узла в treeview
{
//Перебор детей открывамого узла
TTreeNode *child=Node->getFirstChild();
TSearchRec sr;
AnsiString dir,name;
do
{
dir=*((AnsiString *)child->Data);
//Проверка диска на гибкую дискету и вообще отсутствие детей
if((((GetDriveType(dir.c_str())==DRIVE_REMOVABLE) || (GetDriveType(dir.c_str())==DRIVE_CDROM)) && !DiskIn.Contains(ExtractFileDrive(dir)[1])) || FindFirst(dir+"*",faAnyFile,sr)!=0) //Просмотр папок в детях
continue; //Гибкую дискету нельзя отображать из-за обращения к ней при ее отсутствии
do
if((sr.Attr & faDirectory) && sr.Name!="." && sr.Name!="..")
AddChildInNodeTree(child,dir+sr.Name+"\\");
while(FindNext(sr)==0);
FindClose(sr);
}
while((child=Node->GetNextChild(child))!=NULL);
}
void TForm1::DeleteChild(TTreeNode *Node) //Удаление потомков потомков узла (их уже не видно)
{
TTreeNode *child=Node->getFirstChild();
TTreeNode *childchild;
do
while((childchild=child->getFirstChild())!=NULL)
{
delete childchild->Data;
TreeView1->Items->Delete(childchild);
}
while((child=Node->GetNextChild(child))!=NULL);
}
bool CheckExpandedChild(TTreeNode *Node) //Проверка раскрытия ветви хотя бы одного
{ //потомка
bool flag=false;
TTreeNode *child;
if((child=Node->getFirstChild())!=NULL)
do
flag=flag || child->Expanded;
while((child=Node->GetNextChild(child))!=NULL);
return flag;
}
int TForm1::FileAndFolderOperation(char *frombuf, char *tobuf, unsigned int operation)
{ //Осуществление операций над файлами - копирование, перемещение
//удаление, переименование
SHFILEOPSTRUCT OpStruc;
OpStruc.hwnd= Handle;
OpStruc.wFunc= operation;
OpStruc.pFrom= frombuf;
OpStruc.pTo=tobuf;
OpStruc.fFlags=0;
OpStruc.fAnyOperationsAborted= false;
OpStruc.hNameMappings= NULL;
OpStruc.lpszProgressTitle= NULL;
int p=SHFileOperation(&OpStruc);
return p;
}
TListItem *TForm1::AddItemInListView(TSearchRec sr,AnsiString dir)
{ //Добавление записи в listview из sr и каталога dir
TListItem *p;
AnsiString date;
int size=sr.Size/1024;
p=ListView1->Items->Add(); //Добавление нового элемента
FirstUpOtherDown(sr.Name); //Выравнивание у имени символов
DateTimeToString(date,"dd/mm/yy h:nn",FileDateToDateTime(sr.Time));
AnsiString *a;
if(sr.Attr & faDirectory)
{
a=new AnsiString(dir+sr.Name+"\\"); //Сохранение полного имени для доступа
p->sub>Items->Add(""); //Для директорий (папок)
p->sub>Items->Add("Папка");
p->ImageIndex=ImageCloseFolder;
}
else
{
a=new AnsiString(dir+sr.Name);
SHFILEINFO sfi; //Структура содержащая инфу о файле
ZeroMemory(&sfi,sizeof(sfi)); //Очистка
SHGetFileInfo(sr.Name.c_str(),FILE_ATTRIBUTE_NORMAL,&sfi,sizeof(sfi),
SHGFI_USEFILEATTRIBUTES|SHGFI_TYPENAME|SHGFI_ICON | SHGFI_SMALLICON); //Получение данных
TIcon *icon=new TIcon(); //Создание динамической иконки
icon->Handle=sfi.hIcon; //Загрузка в нее дескриптора нужной иконки
int num=ImageList2->AddIcon(icon); //Занесение дескриптора в imagelist
p->ImageIndex=num;
p->sub>Items->Add(AnsiString(size==0?1:size)+" KB"); //2 Добавление размера
p->sub>Items->Add(sfi.szTypeName); //3 Добавление имени типа
ZeroMemory(&sfi,sizeof(sfi));
SHGetFileInfo(sr.Name.c_str(),FILE_ATTRIBUTE_NORMAL,&sfi,sizeof(sfi),
SHGFI_USEFILEATTRIBUTES|SHGFI_TYPENAME|SHGFI_ICON | SHGFI_LARGEICON ); //Получение данных
icon->Handle=sfi.hIcon; //Загрузка в нее дескриптора нужной иконки
ImageList4->AddIcon(icon);
delete icon;
}
p->sub>Items->Add(date); //4 Добавление даты
p->Data=a;
p->Caption=sr.Name; //1 Запись названия
return p;
}
void TForm1::ViewFailAndFolderInListView(AnsiString dir)
{ //Отображение в listview папки указанной dir
for(int i=0;i<ListView1->Items->Count;i++)
delete ListView1->Items->Item[i]->Data; //Очистка данных о полном пути к файлам
ImageList2->Clear();
ImageList4->Clear();
ListView1->Clear(); //Очистка списка
ImageList2->AddImages(ImageList1);
ImageList4->AddImages(ImageList3);
AnsiString path=dir.sub>String(1,3); //Извлечение названия корневого каталога
char inf[20];
unsigned int p=GetDriveType(path.c_str());
if(p==DRIVE_REMOVABLE || p==DRIVE_CDROM)
{
if(GetVolumeInformation(path.c_str(),inf,20,NULL,NULL,NULL,NULL,NULL))
{
if(!(DiskIn.Contains(path[1]))) DiskIn<<path[1];
UpdateTreeView(false);
UpdateLabel();
}
else
{
UpdateTreeView(false);
if(DiskIn.Contains(path[1])) DiskIn>>path[1];
UpdateLabel();
CurrentDir="";
return;
}
}
while(ExtractFileDrive(dir).AnsiCompareIC(dir)!=0 && GetFileAttributes(dir.c_str())==-1)
dir=ExtractFilePath(dir.SetLength(dir.Length()-1));
TSearchRec sr;
if(FindFirst(dir+"*",faAnyFile,sr)!=0) //Просмотр папок в детях
return;
do
{
int Attr=FileGetAttr(dir+sr.Name);
if(Attr==-1 || sr.Name=="." || sr.Name=="..")
continue; //Проверка на отсутствующие в действиетельности папки
AddItemInListView(sr,dir);
}
while(FindNext(sr)==0);
FindClose(sr);
CurrentDir=dir; //Запоминание текущего каталога
double c=10.0;
__int64 FreeSpace,TotalSpace;
if(Sysutils::GetDiskFreeSpaceEx(ExtractFileDrive(dir).c_str(),NULL,TotalSpace,&FreeSpace))
StatusBar1->SimpleText=AnsiString("Объектов: ")+ListView1->Items->Count+" (Свободно на диске "+ AnsiString(((FreeSpace*10)/1024/1024/1024)/c)+" ГБ)";
}
void TForm1::ViewProperty() //Отображение свойств файла папки диска
{
if(CurrentDir=="") return;
if(ListView1->ItemFocused==NULL)
{
if(TreeView1->Selected!=NULL)
{
if(TreeView1->Selected->Level==1)
FPropertyDrive->Prepare(*((AnsiString *)(TreeView1->Selected->Data)));
else if(TreeView1->Selected->Level>1)
FPropertyFile->Prepare(*((AnsiString *)(TreeView1->Selected->Data)));
}
}
else
{
if(ListView1->Selected!=NULL)
FPropertyFile->Prepare(*((AnsiString *)(ListView1->Selected->Data)));
else
{
if(ExtractFileDrive(CurrentDir).AnsiCompareIC(CurrentDir.sub>String(1,CurrentDir.Length()-1))==0)
FPropertyDrive->Prepare(CurrentDir);
else
FPropertyFile->Prepare(CurrentDir);
}
}
UpdateAll(true);
}
void TForm1::PrepareBufForOperationInListView(char * &frombuf) //Подготовка буфера данных
{ //над которыми производится опер
frombuf=new char[ListView1->SelCount*MAX_PATH+1];
if(ListView1->SelCount==1) //Если выделен один элемент то все просто
{ //заполняем frombuf именем
AnsiString sourcestr=*((AnsiString *)(ListView1->Selected->Data));
if((FileGetAttr(sourcestr) & faDirectory)!=0)
sourcestr.SetLength(sourcestr.Length()-1);
strcpy(frombuf,sourcestr.c_str());
finstr(frombuf);
}
else
{
char *temp=frombuf;
bool flag=false; //Если несколько последовательно заполняем именами
for(int i=0;i<ListView1->Items->Count;i++)
if(ListView1->Items->Item[i]->Selected)
{
AnsiString sourcestr=*((AnsiString *)(ListView1->Items->Item[i]->Data));
if((FileGetAttr(sourcestr) & faDirectory)!=0)
sourcestr.SetLength(sourcestr.Length()-1);
if(flag)
strcat0(temp,sourcestr.c_str());
else
{
strcpy(temp,sourcestr.c_str());
flag=true;
}
}
finstr(temp);
}
}
AnsiString TForm1::RenameFileOrFolder(AnsiString NewName)
{
char frombuf[MAX_PATH+1]={'\0'},tobuf[MAX_PATH+1]={'\0'};
if(ListView1->ItemFocused==NULL)
{
if(TreeView1->Selected!=NULL)
if(TreeView1->Selected->Level>1)
{
AnsiString temp;
AnsiString *sourcestr=((AnsiString *)(TreeView1->Selected->Data));
temp=*sourcestr; //Сохранение в темповой переменной старого пути
sourcestr->SetLength(sourcestr->Length()-1);
strcpy(frombuf,sourcestr->c_str()); //Построение нового пути
*sourcestr=ExtractFilePath(*sourcestr)+NewName;
strcpy(tobuf,sourcestr->c_str());
if(FileAndFolderOperation(frombuf,tobuf,FO_RENAME)!=0) //Если операция не удалась
{
*sourcestr=temp; //Возвращаем назад
NewName=ExtractFileName(temp.sub>String(1,temp.Length()));
}
else
*sourcestr=*sourcestr+"\\"; //Если нормально меняем путь
return NewName;
}
}
else
if((ListView1->Selected)!=NULL)
{
bool dir=false;
AnsiString *sourcestr=((AnsiString *)(ListView1->Selected->Data));
AnsiString temp=*sourcestr;
if((FileGetAttr(*sourcestr) & faDirectory)!=0)
{
sourcestr->SetLength(sourcestr->Length()-1);
dir=true;
}
strcpy(frombuf,sourcestr->c_str());
*sourcestr=ExtractFilePath(*sourcestr)+NewName;
strcpy(tobuf,sourcestr->c_str());
if(FileAndFolderOperation(frombuf,tobuf,FO_RENAME)!=0)
{
*sourcestr=temp;
if(dir)
temp.SetLength(temp.Length()-1);
NewName=ExtractFileName(temp);
}
else
if(dir)
*sourcestr=*sourcestr+"\\";
return NewName;
}
}
void TForm1::DeleteFileOrFolder()
{
if(ListView1->ItemFocused==NULL)
{
if(TreeView1->Selected!=NULL)
if(TreeView1->Selected->Level>1)
{
char frombuf[MAX_PATH]={'\0'};
AnsiString sourcestr=*((AnsiString *)(TreeView1->Selected->Data));
sourcestr.SetLength(sourcestr.Length()-1);
strcpy(frombuf,sourcestr.c_str());
FileAndFolderOperation(frombuf,NULL,FO_DELETE);
}
}
else
if((ListView1->Selected)!=NULL)
{
char *frombuf;
PrepareBufForOperationInListView(frombuf);
FileAndFolderOperation(frombuf,NULL,FO_DELETE);
}
UpdateAll(false);
}
void TForm1::ExpandTreeForFile(AnsiString FileName)
{ //Расширение ветвей tree до файла
AnsiString Find="";
TTreeNode *p=TreeView1->Items->Item[0], *child;
child=p->getFirstChild();
bool flag=false;
do
{
flag=false;
int pos=FileName.Pos("\\"); //Вычленение из имени файла папки
Find=Find+FileName.sub>String(1,pos); //прибавление к find
FileName.Delete(1,pos);
if(FileName.Pos("\\")==0)
flag=true; //Критерий окончания
child=p->getFirstChild();
while(1)
{
if(child==NULL)
{
child=AddChildInNodeTree(p,Find); //Если узла вообще нет то создаем его
if(!p->Expanded) //и расширяем его отца
p->Expand(false);
}
if((*(AnsiString *)(child->Data)).AnsiCompareIC(Find)==0)
{
if (flag) //По окончании передаем выделение на этот узел
TreeView1->Selected=child;
else if(!child->Expanded) //если это толлько промежуточная папка
child->Expand(false); //расширяем ветвь
p=child;
break;
}
child=p->GetNextChild(child);
}
}
while(!flag);
}
void TForm1::OpenFileOrFolder()
{ //Происходит открытие файла или папки выделенных в listview
if(ListView1->Selected==NULL) return; //проверка наличия выделенного
AnsiString ww=*((AnsiString *)(ListView1->Selected->Data));
if((FileGetAttr(ww) & faDirectory)!=0) //В случае папки
{
ViewFailAndFolderInListView(ww); //Вызываем отображение папок и файлов
ExpandTreeForFile(ww); //Расширяем treeview до этого файла
}
else
{
ShellExecute(NULL,"open",ww.c_str(),NULL,NULL,SW_RESTORE); //В случае файла
if(GetLastError()) //Выполняем его и проверяем ошибки
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, sub>LANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf, 0, NULL);
// Display the string.
MessageBox( NULL, (char*)lpMsgBuf, "Ошибка", MB_OK|MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
}
}
}
void RecursDelData(TTreeNode *node) //Рекурсивная функция обходит
{ // дочерние узлы и удаляет данные по указателю data
delete node->Data;
TTreeNode *child;
for(child=node->getFirstChild();child!=NULL;child=node->GetNextChild(child))
RecursDelData(child);
}
void TForm1::RecursTree(TTreeNode *node,bool UpdateAllways)
{
AnsiString dir=*((AnsiString *)(node->Data));
TSearchRec sr;
TTreeNode *child;
int num=0;
if(((GetDriveType(dir.c_str())==DRIVE_REMOVABLE) || (GetDriveType(dir.c_str())==DRIVE_CDROM)) && !DiskIn.Contains(ExtractFileDrive(dir)[1]))
return; //Условие: просматривать дискету и диск если отмечено что они есть
if(!UpdateAllways)
{
if(FindFirst(dir+"*",faAnyFile,sr)==0)
do //и продолжить если найден файл
if((sr.Attr & faDirectory) && sr.Name!="." && sr.Name!="..")
num++; //Пересчитываем все папки в данной
while(FindNext(sr)==0);
FindClose(sr);
}
int count=node->Count;
if(UpdateAllways || num!=count) //Сравниваем с количеством узлов потомков
{
if(UpdateAllways || num<count) //Если узлов потомков больше ищем отсутствующую папку
for(child=node->getFirstChild();child!=NULL;)
{
AnsiString t=*(AnsiString *)(child->Data);
if(GetFileAttributes(t.c_str())==-1)
{
TTreeNode *temp=node->GetNextChild(child);
if(child->Selected) node->Selected=true;
RecursDelData(child); //Удаляем данные несуществующей папки и ее потомков
TreeView1->Items->Delete(child); //удаляем узел
child=temp;
}
else
child=node->GetNextChild(child);
}
if(UpdateAllways || num>count) //Если какой-то папки не хватает
{
if(FindFirst(dir+"*",faAnyFile,sr)==0) //Перебираем папки
do
if((sr.Attr & faDirectory) && sr.Name!="." && sr.Name!="..")
{ //Ищем для них узлы
for(child=node->getFirstChild();child!=NULL;child=node->GetNextChild(child))
if((*(AnsiString *)(child->Data)).AnsiCompareIC((dir+sr.Name+"\\"))==0)
break;
if(child==NULL) //если соответствующего узла нет добавляем
AddChildInNodeTree(node,dir+sr.Name+"\\");
}
while(FindNext(sr)==0);
FindClose(sr);
}
}
if(node->Expanded || CheckExpandedChild(node))
{
for(child=node->getFirstChild();child!=NULL;child=node->GetNextChild(child))
RecursTree(child,UpdateAllways);
}
}
void TForm1::UpdateTreeView(bool UpdateAllways) //Обновление treeview
{
TTreeNode *top=TreeView1->Items->Item[0];
TTreeNode *child;
if(top->Expanded)
for(child=top->getFirstChild();child!=NULL;child=top->GetNextChild(child))
RecursTree(child, UpdateAllways);
TreeView1->AlphaSort();
}
void TForm1::UpdateListView(bool UpdateAllways) //Обновление списка listview
{
if(CurrentDir=="") return; //Если ни один каталог не отображается
if(GetFileAttributes(CurrentDir.c_str())==-1)
{ //Если текущего каталога уже не существует
ViewFailAndFolderInListView(CurrentDir); //отображаем его ридительский каталог
return;
}
TSearchRec sr;
TListItem *item;
int num=0; //подсчет количества файлов в папке
if(!UpdateAllways)
{
if(FindFirst(CurrentDir+"*",faAnyFile,sr)==0)
do //и продолжить если найден файл
if(sr.Name!="." && sr.Name!="..")
num++; //Пересчитываем все папки в данной
while(FindNext(sr)==0);
FindClose(sr);
}
int count=ListView1->Items->Count;
if(UpdateAllways || num!=count) //Сравниваем с количеством узлов потомков
{
if(UpdateAllways || num<count) //Если записей больше чем файлов
for(int i=0;i<ListView1->Items->Count;i++) //ищем уже отсутствующие в действительности
{
AnsiString t=*(AnsiString *)(ListView1->Items->Item[i]->Data);
if(GetFileAttributes(t.c_str())==-1)
{
delete ListView1->Items->Item[i]->Data; //Удаляем вспомогательные данные для него
ListView1->Items->Delete(i); //удаляем узел
i--;
}
}
if(UpdateAllways || num>count) //Если файлов не хватает
{
if(FindFirst(CurrentDir+"*",faAnyFile,sr)==0) //Перебираем файлы
do
if(sr.Name!="." && sr.Name!="..")
{ //Ищем для них записи
int i;
for(i=0;i<ListView1->Items->Count;i++)
if((*(AnsiString *)(ListView1->Items->Item[i]->Data)).AnsiCompareIC(CurrentDir+sr.Name+((sr.Attr & faDirectory)?"\\":""))==0)
break;
if(i==ListView1->Items->Count) //если соответствующего узла нет добавляем
AddItemInListView(sr,CurrentDir);
}
while(FindNext(sr)==0);
FindClose(sr);
}
}
}
void TForm1::UpdateLabel() //Обновление меток диска
{
TTreeNode *child, *node=TreeView1->Items->Item[0];
for(child=node->getFirstChild();child!=NULL;child=node->GetNextChild(child))
{
AnsiString path=*((AnsiString *)child->Data);
AnsiString text=child->Text;
char inf[20];
unsigned int p=GetDriveType(path.c_str());
if(((p==DRIVE_REMOVABLE || p==DRIVE_CDROM) && (DiskIn.Contains(path[1]))) ||
(p!=DRIVE_REMOVABLE && p!=DRIVE_CDROM))
{
if(GetVolumeInformation(path.c_str(),inf,20,NULL,NULL,NULL,NULL,NULL))
{
text.Delete(1,text.Pos("(")-1);
FirstUpOtherDown(inf);
child->Text=AnsiString(inf)+" "+text;
}
else
{
text.Delete(1,text.Pos("(")-1);
child->Text=" "+text;
ViewFailAndFolderInListView(path);
}
}
else
{
text.Delete(1,text.Pos("(")-1);
child->Text=" "+text;
}
}
}
void TForm1::UpdateAll(bool UpdateAllways) //Обновление всего
{
UpdateTreeView(UpdateAllways); //Обновление дерева папок
UpdateListView(UpdateAllways); //Обновление списка файлов
UpdateLabel();
double c=10.0;
if(CurrentDir!="")
{
__int64 FreeSpace,TotalSpace;
if(Sysutils::GetDiskFreeSpaceEx(ExtractFileDrive(CurrentDir).c_str(),NULL,TotalSpace,&FreeSpace))
StatusBar1->SimpleText=AnsiString("Объектов: ")+ListView1->Items->Count+" (Свободно на диске "+ AnsiString(((FreeSpace*10)/1024/1024/1024)/c)+" ГБ)";
}
}
void TForm1::PasteFileFromClipboard() //Вставить из буфера
{
if(CurrentDir=="") return;
char *frombuf, *temp;
char tobuf[MAX_PATH+1]={'\0'};
int nCount,i; //Число копируемых объектов
Pointer Data;
char * lpDroppedFile;
OpenClipboard(NULL); //Открывает clipboard для текущего процесса
if (IsClipboardFormatAvailable(CF_HDROP))
{
Data=GetClipboardData(CF_HDROP); //Получение указателя на данные
if(Data==0) { CloseClipboard(); return; } //Нечего забирать
nCount= DragQueryFile(Data, 0xFFFFFFFF, NULL, 0); //Получение количества
temp=frombuf=new char[MAX_PATH*nCount];
if (nCount > 0)
{
lpDroppedFile=(char *)AllocMem(MAX_PATH + 1); //Выделение памяти под массив
for (i= 0;i<nCount;i++) //с названиями копирумых объектов
{
DragQueryFile(Data, i, lpDroppedFile, MAX_PATH); //Собственно получение имен этих объектов
if(i!=0)
strcat0(temp,lpDroppedFile); //Добавление к frombuf
else
strcpy(temp,lpDroppedFile);
}
finstr(temp);
free(lpDroppedFile); //Освобождение
strcpy(tobuf,CurrentDir.c_str());
}
long lngEffect;
long lngFormat = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
HANDLE hGlobal = GetClipboardData(lngFormat);
if(hGlobal)
MoveMemory(&lngEffect,hGlobal, 4);
if((lngEffect & DROPEFFECT_COPY) == DROPEFFECT_COPY)
FileAndFolderOperation(frombuf,tobuf , FO_COPY);
if((lngEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
FileAndFolderOperation(frombuf,tobuf , FO_MOVE);
UpdateAll(false);
}
CloseClipboard();
}
void TForm1::CopyFileToClipboard(bool Copy)
{
if(CurrentDir=="") return;
char *frombuf;
unsigned int uDropEffect, uBufLen;
DROPFILES dropFiles;
unsigned int uGblLen,uDropFilesLen;
HGLOBAL hGblFiles,hGblEffect;
char *szData,*szFileList;
DWORD *dwDropEffect;
uDropEffect=RegisterClipboardFormat("Preferred DropEffect"); //Регистрация формата
//для указания типа копирования
hGblEffect=GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE,sizeof(DWORD));
dwDropEffect=(DWORD*)GlobalLock(hGblEffect); //Выделение памяти под хранение
if(Copy) //инфы о виде перемещения
*dwDropEffect=DROPEFFECT_COPY; //Запись этой инфы
else
*dwDropEffect=DROPEFFECT_MOVE;
GlobalUnlock(hGblEffect); //Разлочивание памяти
uDropFilesLen=sizeof(DROPFILES); //Заполнение структуры содержащей инфу
dropFiles.pFiles =uDropFilesLen; //о строке с именами перемещаемых файлов
dropFiles.pt.x=0;
dropFiles.pt.y=0;
dropFiles.fNC =FALSE;
dropFiles.fWide =FALSE;//TRUE;
if(ListView1->ItemFocused==NULL)
{
if(TreeView1->Selected!=NULL) //Если в фокусе находится treeview
if(TreeView1->Selected->Level>1)
{
AnsiString sourcestr=*((AnsiString *)(TreeView1->Selected->Data));
sourcestr.SetLength(sourcestr.Length()-1);
frombuf=new char[MAX_PATH+1];
strcpy(frombuf,sourcestr.c_str());
finstr(frombuf);
}
else
return; //Выход в том случае если в фокусе Диск или Мой компьютер
}
else if((ListView1->Selected)!=NULL)
PrepareBufForOperationInListView(frombuf);
uBufLen=lengthfinstr(frombuf);
uGblLen=uDropFilesLen+uBufLen+2;
hGblFiles= GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE, uGblLen);
szData=(char*)GlobalLock(hGblFiles);
memcpy(szData,&dropFiles,uDropFilesLen);
szFileList=szData+uDropFilesLen;
memcpy(szFileList,frombuf,uBufLen);
/*MultiByteToWideChar(CP_ACP,MB_COMPOSITE,
frombuf,uBufLen,(WCHAR *)szFileList,uBufLen*2+8);*/
GlobalUnlock(hGblFiles);
if( OpenClipboard(NULL) )
{
EmptyClipboard();
SetClipboardData( CF_HDROP, hGblFiles );
SetClipboardData(uDropEffect,hGblEffect);
CloseClipboard();
}
}
void TForm1::CreateFol() //Создает папку в текущем каталоге
{
if(CurrentDir=="") return;
AnsiString c="Новая папка",dir; //Производит поиск отсутствующей папки
for(int i=1;(GetFileAttributes((dir=CurrentDir+c+i).c_str()))!=-1;i++);
if(ListView1->Selected!=NULL) //Если есть выделенные узлы
for(int i=0;i<ListView1->Items->Count;i++) //отменяем выделение
ListView1->Items->Item[i]->Selected=false;
if(CreateDir(dir)) //Создает ее
{
TSearchRec sr;
FindFirst(dir,faDirectory,sr);
TListItem *p=AddItemInListView(sr,ExtractFilePath(dir));
ListView1->ItemFocused=p;
p->Selected=true;
p->EditCaption();
}
UpdateAll(false);
}
//*************************************************************************
//------------------------------------------------------------------------
//***********************************************************************
__fastcall TForm1::TForm1(TComponent* Owner) //Конструктор формы
: TForm(Owner)
{
ShortDateFormat="dd/mm/yy";
DateSeparator = '/';
TimeSeparator=':';
ShortTimeFormat="h:nn";
AnsiString *a=new AnsiString("");
TreeView1->Items->Item[0]->Data=a;
head=TreeView1->Items->Item[0]; //Сохранение корня
GetDrives(); //Загрузка дисков
ShowDrives(); //Отображение в treview
TreeView1->AlphaSort();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TreeView1Expanding(TObject *Sender,
TTreeNode *Node, bool &AllowExpansion)//Событие - открытие узла
{
DragnDrop=false; //Запрещение перемещения
TreeView1->Items->BeginUpdate();
tpItem=TreeView1->TopItem; //Сохранение верхнего узла
if(!CheckExpandedChild(Node)) //Если ни один из потомков не расширен
ViewChild(Node);
TreeView1->AlphaSort(); //Сортировка
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TreeView1Compare(TObject *Sender, TTreeNode *Node1,
TTreeNode *Node2, int Data, int &Compare) //Функция сравнения
{
if(Node1->Level==1) //Для упорядочивания treeview
Compare=Node1->Text[Node1->Text.Length()-2]>Node1->Text[Node1->Text.Length()-2]?1:-1;
else
Compare=Node1->Text.AnsiCompare(Node2->Text);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TreeView1Expanded(TObject *Sender, TTreeNode *Node)
{ //Сообщение об окончании
TTreeNode * temp=TreeView1->TopItem; //Раскрытия списка
TreeView1->TopItem=tpItem; //Проверка выхода конца открытой ветви за экран
if((TreeView1->GetNodeAt(TreeView1->Width/2,TreeView1->ClientHeight-1))!=NULL)
{ //Если это так то сдвигаем всю ветвь вверх автоматом
int p=(TreeView1->GetNodeAt(TreeView1->Width/2,TreeView1->ClientHeight-1))->AbsoluteIndex;
if(p<=Node->GetLastChild()->AbsoluteIndex) TreeView1->TopItem=temp;
} //если нет то ставим первым сохранненый ранее первый элемент
TreeView1->Items->EndUpdate();
DragnDrop=true; //Разрешение перемещения
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TreeView1Collapsing(TObject *Sender,
TTreeNode *Node, bool &AllowCollapse) //Событие - перед свертыванием
{
DragnDrop=false;
TreeView1->Items->BeginUpdate();
if(!CheckExpandedChild(Node)) //Если ветвь ни одного из потомков не расширена
DeleteChild(Node); //Удаление детей детей
TreeView1->Items->EndUpdate();
DragnDrop=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TreeView1Editing(TObject *Sender, TTreeNode *Node,
bool &AllowEdit)
{
if(Node->Level<2) AllowEdit=false; //Запрет на редактирование Мой комп и названий дисков
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1Compare(TObject *Sender, TListItem *Item1,
TListItem *Item2, int Data, int &Compare)
{
bool temp1=false, temp2=false;
if(((FileGetAttr(*((AnsiString *)Item1->Data))) & faDirectory)!=0)
temp1=true;
if(((FileGetAttr(*((AnsiString *)Item2->Data))) & faDirectory)!=0)
temp2=true;
AnsiString s1,s2;
switch(ColumnToSort)
{
case 0:
if(temp1==temp2)
Compare=(Item1->Caption).AnsiCompare(Item2->Caption);
else
Compare=temp2?1:-1;
break;
case 2:
if(temp1==temp2)
Compare=(Item1->sub>Items->Strings[1]).AnsiCompare(Item2->sub>Items->Strings[1]);
else
Compare=temp2?1:-1;
break;
case 1:
if(temp1) s1="0 ";
else s1= Item1->sub>Items->Strings[0];
if(temp2) s2="0 ";
else s2= Item2->sub>Items->Strings[0];
s1=s1.sub>String(1,s1.Pos(" ")-1);
s2=s2.sub>String(1,s2.Pos(" ")-1);
Compare=StrToInt(s1)>StrToInt(s2)?1:-1;
break;
case 3:
TDateTime dt1=StrToDateTime(Item1->sub>Items->Strings[2]);
TDateTime dt2=StrToDateTime(Item2->sub>Items->Strings[2]);
if(temp1==temp2)
Compare=dt1>dt2?1:-1;
else
Compare=temp2?1:-1;
break;
}
Compare*=Direct;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1DblClick(TObject *Sender)
{ //Двойной клик на ListView
OpenFileOrFolder();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if(DragnDrop && Button == mbLeft) //Событие по нажатию мыши и начало перемещения
{
if(Shift.Contains(ssCtrl))
type_file_operation_drag_drop=FO_COPY;
else
type_file_operation_drag_drop=FO_MOVE;
ListView1->BeginDrag(false,5);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TreeView1DragOver(TObject *Sender, TObject *Source,
int X, int Y, TDragState State, bool &Accept)
{ //Процесс перетаскивания
Accept=(TreeView1->GetNodeAt(X,Y)!=NULL) && (Source->ClassNameIs("TListView") || Source->ClassNameIs("TTreeView"));
} //Даем возможность положить объект если есть куда класть и объект из list и tree
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1DragOver(TObject *Sender, TObject *Source,
int X, int Y, TDragState State, bool &Accept)
{
TListItem *p=ListView1->GetItemAt(X,Y);
Accept=(p!=NULL) && ((FileGetAttr(*((AnsiString *)(p->Data))) & faDirectory) !=0) &&
(Source->ClassNameIs("TListView") || Source->ClassNameIs("TTreeView"));
//Даем возможность положить если есть куда если это папка и объект из list или tree
if((StyleListView==vsIcon || StyleListView==vsSmallIcon) && !Accept && p==NULL)
Accept=true;
//в случае значков даем возможность положить значок в пустое место
}
//---------------------------------------------------------------------------
void strcat0(char * &dest,char *source)
{ //Объединение двуч строк с оставлением между ними
for(;(*dest)!='\0';dest++); //нулевого символа
for(dest++;(*source!='\0');dest++,source++)
*dest=*source;
*dest='\0';
}
void finstr(char *dest)
{
for(;(*dest)!='\0';dest++);
dest++;
*dest='\0';
}
unsigned int lengthfinstr(char *dest)
{
unsigned int l=0;
do
{
for(;(*dest)!='\0';dest++,l++);
dest++;
l++;
}
while((*dest)!='\0');
return l+1;
}
void __fastcall TForm1::ListView1DragDrop(TObject *Sender, TObject *Source,
int X, int Y)
{
int operation=type_file_operation_drag_drop;
if(ListView1->GetItemAt(X,Y)==NULL)
{ //Если перенос делается на пустое место
ListView1->Selected->Position=Point(X,Y); //просто меняем место значка и выходим
return;
}
if(Source->ClassNameIs("TListView")) //Если объект перетащен из listview
{ //извлекаем нужные папки и делаем операцию
char *frombuf, tobuf[MAX_PATH+1]={'\0'};
TListView *sender=(TListView *)Sender;
PrepareBufForOperationInListView(frombuf);
AnsiString senderstr=*((AnsiString *)(sender->GetItemAt(X,Y)->Data));//+ExtractFileName(*((AnsiString *)(source->Selected->Data)));
strcpy(tobuf,senderstr.c_str()); //Вызываем функции и указываем операцию
FileAndFolderOperation(frombuf,tobuf,operation);
}
if(Source->ClassNameIs("TTreeView"))
{
char frombuf[MAX_PATH+1]={'\0'}, tobuf[MAX_PATH+1]={'\0'};
TTreeView *source=(TTreeView *)Source;
TListView *sender=(TListView *)Sender;
AnsiString sourcestr=*((AnsiString *)(source->Selected->Data));
AnsiString senderstr=*((AnsiString *)(sender->GetItemAt(X,Y)->Data));//+ExtractFileName(*((AnsiString *)(source->Selected->Data)));
sourcestr.SetLength(sourcestr.Length()-1);
strcpy(frombuf,sourcestr.c_str());
strcpy(tobuf,senderstr.c_str());
FileAndFolderOperation(frombuf,tobuf,operation);
}
UpdateAll(false); //Обновление
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TreeView1DragDrop(TObject *Sender, TObject *Source,
int X, int Y) //Окончание перетаскивания
{
int operation=type_file_operation_drag_drop;
if(Source->ClassNameIs("TListView")) //Если объект перетащен из listview
{ //извлекаем нужные папки и делаем операцию
char *frombuf, tobuf[MAX_PATH+1]={'\0'};
TTreeView *sender=(TTreeView *)Sender;
PrepareBufForOperationInListView(frombuf);
AnsiString senderstr=*((AnsiString *)(sender->GetNodeAt(X,Y)->Data));//+ExtractFileName(*((AnsiString *)(source->Selected->Data)));
strcpy(tobuf,senderstr.c_str()); //Вызываем функции и указываем операцию
FileAndFolderOperation(frombuf,tobuf,operation);
}
if(Source->ClassNameIs("TTreeView"))
{
TTreeView *source=(TTreeView *)Source;
TTreeView *sender=(TTreeView *)Sender;
char frombuf[MAX_PATH+1]={'\0'}, tobuf[MAX_PATH]={'\0'};
AnsiString sourcestr=*((AnsiString *)(source->Selected->Data));
AnsiString senderstr=*((AnsiString *)(sender->GetNodeAt(X,Y)->Data));//+ExtractFileName(*((AnsiString *)(source->Selected->Data)));
sourcestr.SetLength(sourcestr.Length()-1);
strcpy(frombuf,sourcestr.c_str());
strcpy(tobuf,senderstr.c_str());
FileAndFolderOperation(frombuf,tobuf,operation);
}
UpdateAll(false); //Обновление
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TreeView1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if(DragnDrop && Button == mbLeft) //начало перетаскивания по нажатию на treeview
{
if(Shift.Contains(ssCtrl))
type_file_operation_drag_drop=FO_COPY;
else
type_file_operation_drag_drop=FO_MOVE;
TreeView1->BeginDrag(false,5);
}
}
void __fastcall TForm1::TreeView1Edited(TObject *Sender, TTreeNode *Node,
AnsiString &S)
{
S=RenameFileOrFolder(S);
UpdateTreeView(false);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1Edited(TObject *Sender, TListItem *Item,
AnsiString &S)
{
S=RenameFileOrFolder(S);
UpdateTreeView(false);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::NRenameClick(TObject *Sender)
{
if(ListView1->ItemFocused==NULL)
{
if(TreeView1->Selected!=NULL)
if(TreeView1->Selected->Level>1)
TreeView1->Selected->EditText();
}
else
if((ListView1->Selected)!=NULL)
ListView1->Selected->EditCaption();
}
void __fastcall TForm1::TreeView1ContextPopup(TObject *Sender,
TPoint &MousePos, bool &Handled)
{
TTreeNode *node;
if((node=TreeView1->GetNodeAt(MousePos.x,MousePos.y))!=NULL)
{
ListView1->ItemFocused=NULL;
TreeView1->Selected=node;
if(TreeView1->Selected->Level>0)
ViewFailAndFolderInListView(*((AnsiString *)(TreeView1->Selected->Data)));
node->Focused=true;
}
else
TreeView1->Selected=NULL;
if(TreeView1->Selected!=NULL && TreeView1->Selected->Level>0)
Handled=false;
else
Handled=true;
PNOpen->Visible=false;
PNView->Visible=false;
PNSort->Visible=false;
PNUpdate->Visible=false;
PNProperty->Visible=true;
if(TreeView1->Selected->Level>1)
{
PNCut->Visible=true;
PNCopy->Visible=true;
PNDelete->Visible=true;
PNRename->Visible=true;
}
else
{
PNCut->Visible=false;
PNCopy->Visible=false;
PNDelete->Visible=false;
PNRename->Visible=false;
}
OpenClipboard(NULL); //Проверка возможности вставки
if(IsClipboardFormatAvailable(CF_HDROP))
PNPaste->Enabled=true;
else
PNPaste->Enabled=false;
CloseClipboard();
}
//-----------------------------------------------------------
Листинг PropertyFile.cpp
TFPropertyFile *FPropertyFile;
//---------------------------------------------------------------------------
__fastcall TFPropertyFile::TFPropertyFile(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void TFPropertyFile::Set_Change(AnsiString Name,WIN32_FILE_ATTRIBUTE_DATA &attr)
{
if (ENameFile->Modified) //Сохранение изменений
{ //Если изменнео имя файла папки
if((FileGetAttr(Name) & faDirectory)!=0)
Name.SetLength(Name.Length()-1);
char frombuf[1000]={'\0'}, tobuf[1000]={'\0'};
strcpy(frombuf,Name.c_str());
strcpy(tobuf,(ExtractFilePath(Name)+ENameFile->Text).c_str());
Form1->FileAndFolderOperation(frombuf,tobuf,FO_RENAME); //Переименовываем
}
//Сохранение атрибутов
if(CBArchiv->Checked) attr.dwFileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
else attr.dwFileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE;
if(CBReadOnly->Checked) attr.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
else attr.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
if(CBHide->Checked) attr.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
else attr.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
if(CBSystem->Checked) attr.dwFileAttributes |= FILE_ATTRIBUTE_SYSTEM;
else attr.dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;
SetFileAttributes(Name.c_str(),attr.dwFileAttributes); //Установка
ENameFile->Modified=false;
}
void TFPropertyFile::Get_Size_Folder(AnsiString dir)
{
TSearchRec sr;
if(FindFirst(dir+"*",faAnyFile,sr)!=0) //Просмотр папок в детях
return;
do
{
int Attr=FileGetAttr(dir+sr.Name);
if(Attr==-1 || sr.Name=="." || sr.Name=="..")
continue; //Проверка на отсутствующие в действиетельности папки
if(sr.Attr & faDirectory)
{
num_folder++;
Get_Size_Folder(dir+sr.Name+"\\"); //Сохранение полного имени для доступа
}
else
{
num_files++;
size+=sr.Size;
unsigned long temp;
temp=sr.Size;
if((temp/byte_in_cluster*byte_in_cluster)!=temp) //Проверка влезания файла
temp=(temp/byte_in_cluster+1)*byte_in_cluster;
size_on_disk+=temp;
}
}
while(FindNext(sr)==0);
FindClose(sr);
}
void TFPropertyFile::Prepare(AnsiString Name)
{
//Подготовка данных и показ свойств файла
unsigned long int byte_in_sector,sector_in_cluster;
GetDiskFreeSpace((ExtractFileDrive(Name)+"\\").c_str(),§or_in_cluster,
&byte_in_sector,NULL,NULL);
byte_in_cluster=sector_in_cluster*byte_in_sector;
Name_File=Name;
GetFileAttributesEx(Name.c_str(),GetFileExInfoStandard,&attr);
FILETIME ft;
SYSTEMTIME st;
AnsiString date;
TDateTime dt;
if((FileGetAttr(Name) & faDirectory)!=0) //Если свойства папки
{
Graphics::TBitmap *i=new Graphics::TBitmap; //Загрузка иконки папки
Form1->ImageList3->GetBitmap(ImageCloseFolder,i);
IIconFile->Picture->Bitmap->Assign(i);
delete i;
ENameFile->Text=ExtractFileName(Name.sub>String(1,Name.Length()-1));
LTypeFile->Caption="Папка"; //Загрузка названия
LFolder->Caption=ExtractFilePath(Name.sub>String(1,Name.Length()-1));
num_files=num_folder=size=size_on_disk=0; //Запуск рекурсивной функции считающей
Get_Size_Folder(Name); //размер папки кол-во файлов и папок в ней
LSize->Caption=AnsiString(FormatFloat("#,##0", size/1024))+" KB ("+AnsiString(FormatFloat("#,##0", size))+ " байт)";
LOnDisk->Caption=AnsiString(FormatFloat("#,##0", size_on_disk/1024))+" KB ("+AnsiString(FormatFloat("#,##0", size_on_disk))+ " байт)";
LName->Caption="Содержит :";
LOpen->Caption=AnsiString("Файлов: ")+num_files+" ; Папок: "+num_folder;
}
else //Если свойства файла
{
SHFILEINFO sfi; //Структура содержащая инфу о файле
ZeroMemory(&sfi,sizeof(sfi)); //Очистка
SHGetFileInfo(Name.c_str(),FILE_ATTRIBUTE_NORMAL,&sfi,sizeof(sfi),
SHGFI_USEFILEATTRIBUTES|SHGFI_TYPENAME|SHGFI_ICON | SHGFI_LARGEICON ); //Получение данных
TIcon *icon=new TIcon(); //Создание динамической иконки
icon->Handle=sfi.hIcon; //Загрузка в нее дескриптора нужной иконки
IIconFile->Picture->Icon->Assign(icon); //Занесение дескриптора в imagelist
delete icon;
ENameFile->Text=ExtractFileName(Name);
LTypeFile->Caption=(AnsiString)(sfi.szTypeName);//Занесение имени типа
LFolder->Caption=ExtractFilePath(Name); //Занесение каталога
//----------------------------------------------
//Получение атрибутов - дат размера атрибутов
unsigned long int size=attr.nFileSizeHigh<<16 | attr.nFileSizeLow;
//Вывод размеров
LSize->Caption=AnsiString(size/1024)+" KB ("+AnsiString(size)+ " байт)"; //размера
if((size/byte_in_cluster*byte_in_cluster)!=size) //Проверка влезания файла
size=(size/byte_in_cluster+1)*byte_in_cluster; //в кластеры и наличия свободного места в них
LOnDisk->Caption=AnsiString(size/1024)+" KB ("+AnsiString(size)+ " байт)";
LName->Caption="Открыт :";
//----------------------------------------------------
//Определение дат
//Даты доступа
FileTimeToLocalFileTime(&(attr.ftLastAccessTime), &ft);
FileTimeToSystemTime( &ft, &st);
dt=SystemTimeToDateTime(st);
DateTimeToString(date,"d mmm yyyy г.",dt);
LOpen->Caption=date; //Запись даты доступа
//----------------------------------------
}
//Даты создания
FileTimeToLocalFileTime(&(attr.ftCreationTime), &ft);
FileTimeToSystemTime( &ft, &st);
dt=SystemTimeToDateTime(st);
DateTimeToString(date,"d mmm yyyy г., hh:nn:ss",dt);
LCreate->Caption=date; //Запись даты создания
///Даты изменения
FileTimeToLocalFileTime(&(attr.ftLastWriteTime), &ft);
FileTimeToSystemTime( &ft, &st);
dt=SystemTimeToDateTime(st);
DateTimeToString(date,"d mmm yyyy г., hh:nn:ss",dt);
LWrite->Caption=date; //Запись даты изменения
CBArchiv->Checked=attr.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE;
CBReadOnly->Checked=attr.dwFileAttributes & FILE_ATTRIBUTE_READONLY;
CBHide->Checked=attr.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN;
CBSystem->Checked=attr.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM;
ENameFile->Modified=false;
if(FPropertyFile->ShowModal()==mrOk) //Показ формы
Set_Change(Name,attr);
}
void __fastcall TFPropertyFile::BtApplyClick(TObject *Sender)
{ //Щелчок на применить
Set_Change(Name_File,attr); //Вызов функции сохранения изменений
}
//---------------------------------------------------------------------------
Листинг PropertyDrive.cpp
TFPropertyDrive *FPropertyDrive;
//---------------------------------------------------------------------------
__fastcall TFPropertyDrive::TFPropertyDrive(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void TFPropertyDrive::Prepare(AnsiString Name)
{
Name_Drive=Name;
Graphics::TBitmap *i=new Graphics::TBitmap; //Загрузка иконки папки
Caption="Свойства: Диск "+Name.sub>String(1,2);
switch(GetDriveType(Name.c_str())) //Загрузка image
{
case DRIVE_REMOVABLE:
LType->Caption="Дисковод";
Form1->ImageList3->GetBitmap(ImageFloppy,i);
break;
case DRIVE_FIXED:
case DRIVE_RAMDISK:
LType->Caption="Жесткий диск";
Form1->ImageList3->GetBitmap(ImageDrive,i);
break;
case DRIVE_CDROM:
LType->Caption="CD-дисковод";
Form1->ImageList3->GetBitmap(ImageCD,i);
break;
default:
LType->Caption="Неизвестный дисковод";
Form1->ImageList3->GetBitmap(ImageWindows,i);
break;
}
IIconDisk->Picture->Bitmap->Assign(i);
delete i;
char volume[20],filesystem[20];
if(GetVolumeInformation(Name.c_str(),volume,20,NULL,NULL,NULL,filesystem,20))
{
ELabelDisk->Text=volume;
LFileSystem->Caption=filesystem;
}
else
{
ELabelDisk->Text="";
LFileSystem->Caption="";
}
__int64 FreeSpace,TotalSpace,TakenSpace;
Chart1->Series[0]->Clear();
if(Sysutils::GetDiskFreeSpaceEx(Name.c_str(),NULL,TotalSpace,&FreeSpace))
{
double c=10.0;
TakenSpace=TotalSpace-FreeSpace;
LTaken1->Caption=AnsiString(FormatFloat("#,##0", TakenSpace))+" байт";
LTaken2->Caption=AnsiString(((TakenSpace*10)/1024/1024/1024)/c)+" ГБ";
LFree1->Caption=AnsiString(FormatFloat("#,##0", FreeSpace))+" байт";
LFree2->Caption=AnsiString(((FreeSpace*10)/1024/1024/1024)/c)+" ГБ";
LCapacity1->Caption=AnsiString(FormatFloat("#,##0", TotalSpace))+" байт";
LCapacity2->Caption=AnsiString(((TotalSpace*10)/1024/1024/1024)/c)+" ГБ";
Image1->Canvas->Brush->Color=clRed;
Image1->Canvas->FillRect(Rect(0,0,Image1->Width,Image1->Height));
Chart1->Series[0]->Add(TakenSpace,"1",clRed);
Image2->Canvas->Brush->Color=clGreen;
Image2->Canvas->FillRect(Rect(0,0,Image2->Width,Image2->Height));
Chart1->Series[0]->Add(FreeSpace,"2",clGreen);
Chart1->View3DOptions->Elevation=290;
}
else
{
LTaken1->Caption="0 байт";
LTaken2->Caption="0 байт";
LFree1->Caption="0 байт";
LFree2->Caption="0 байт";
LCapacity1->Caption="0 байт";
LCapacity2->Caption="0 байт";
Image1->Canvas->Brush->Color=clRed;
Image1->Canvas->FillRect(Rect(0,0,Image1->Width,Image1->Height));
Chart1->Series[0]->Add(100,"1",clRed);
Image2->Canvas->Brush->Color=clGreen;
Image2->Canvas->FillRect(Rect(0,0,Image2->Width,Image2->Height));
Chart1->View3DOptions->Elevation=290;
}
ELabelDisk->Modified=false;
if(FPropertyDrive->ShowModal()==mrOk)
{
if(ELabelDisk->Modified)
SetVolumeLabel(Name.c_str(),ELabelDisk->Text.c_str());
}
}
void __fastcall TFPropertyDrive::BtApplyClick(TObject *Sender)
{
if(ELabelDisk->Modified)
SetVolumeLabel(Name_Drive.c_str(),ELabelDisk->Text.c_str());
ELabelDisk->Modified=false;
}
//---------------------------------------------------------------------------
Список использованной литературы
А.Я. Архангельский. Программирование в C++ Builder 6. – М.: ЗАО «Издательство БИНОМ», 2003 г. – 1152 с.
А.Я. Архангельский. Справочное пособие. Книга 2. Классы и компоненты. – М.: Бином-Пресс, 2002 г. –528 с.
http://rsdn.ru/
http://www.sources.ru/
http://msdn.microsoft.com/