menu
  Home  ==>  papers  ==>  colibri_utilities  ==>  directory_favorite_list   

Directory Favorite List - Felix John COLIBRI.


1 - Directory Favorite List

When we are handling projects with some deeply nested file structure, the Windows File Explorer does not allow quick moves from one directory to an other.

The purpose of the favorite list component is

  • to display in a tListBox the names of our favorite pathes
  • to set the current Windows directory by simply clicking on one of those names



2 - Mini How To

Nearly all of our Delphi utilities main window use the following structure:
  • on the left
    • a directory favorite list
    • a tDirectoryListBox
    • a tFileListBox
  • on the right, a display area (a tMemo)
standard_utility_layout

and :

  • to ad an item to the favorite list,
       select a new directory in the tDirectoryListbox, for instance D:\programs\ 
       type "+"
       a input form is displayed
       type the name of this favorite, for instance
      article_programs

    add_a_favorite

       type enter
       the new favorite is added at the end of the favorite list

    new_favorite_list

    at the same time

    • the name of the item and the selected directory are saved in a file. This file is stored in a sub-directory of the .EXE called favorites\  and the name of this file is the concatenation of the project name and "_favorites". In our case :
        directory_favorite_list_favorites.txt
    • the content of this file is displayed in the display area

  • to delete a favorite
       select the favorite item to delete
       type "-"
  • to reorder the items, use drag and drop

  • to navigate to one of the directories, we simply click the item in the favorite list



3 - the Delphi source code

The code is very straightforward
  • the c_favorite_path is defined by :

    c_favorite_path// one "favorite_path"
       Class(c_basic_object)
         // -- m_name: the displayed name in the memos
         // -- the m_parameter is not currently used (could be a Mask)
         m_pathm_parameterString;

         Constructor create_favorite_path(p_namep_pathp_parameterString);
         Function f_display_favorite_pathString;
         Function f_c_selfc_favorite_path;
         Function f_normalized_parameter_listString;

         Destructor DestroyOverride;
       End// c_favorite_path

    where

    • m_name is the item name
    • m_path is the directory
  • the list of favorites is managed by a tStringList container:

    c_favorite_path_list// "favorite_path" list
       Class(c_basic_object)
         // -- m_name: the full file name
         m_c_favorite_path_listtStringList;

         m_c_directory_listbox_reftDirectoryListbox;
         m_c_panel_reftPanel;
         m_c_list_boxtListBox;

         m_full_file_nameString;

         Constructor create_favorite_path_list(p_nameString;
             p_c_panel_reftPanel;
             p_c_directory_listbox_reftDirectoryListbox);

         Function f_favorite_path_countInteger;
         Function f_c_favorite_path(p_favorite_path_indexInteger): c_favorite_path;
         Function f_index_of(p_favorite_path_nameString): Integer;
         Function f_c_find_by_favorite_path(p_favorite_path_nameString): c_favorite_path;
         Procedure add_favorite_path(p_favorite_path_nameString
             p_c_favorite_pathc_favorite_path);
         Function f_c_add_favorite_path(p_favorite_path_namep_pathp_parameterString): 
             c_favorite_path;
         Function f_c_add_unique_favorite_path(p_favorite_path_namep_path
             p_parameterString): c_favorite_path;
         Function f_c_delete_favorite_path(p_favorite_path_indexInteger): c_favorite_path;

         Procedure display_favorite_path_list;

         Function f_path_name_index(p_path_nameString): Integer;
         Procedure create_listbox;

         Procedure handle_favorite_listbox_click(p_c_sendertObject);
         Procedure handle_listbox_keypress(p_c_sendertObjectVar pv_keyChar);

         Procedure handle_directory_listbox_keypress(p_c_sendertObjectVar pv_keyChar);
         Procedure handle_directory_listbox_click(p_c_sendertObject);

         Procedure handle_directory_listbox_drag_over(
             p_c_senderp_c_sourceTObjectp_xp_yInteger;
             p_drag_stateTDragStateVar pv_acceptBoolean);
         Procedure handle_directory_listbox_drag_dop(
             p_c_senderp_c_sourceTObjectp_xp_yInteger);

         Procedure load_from_file(p_full_file_nameString);
         Procedure save_to_file;

         Destructor DestroyOverride;
       End// c_favorite_path_list

    The class contains

    • a reference to the tDirectoryLisbox (to handle the "+" and the directory selection
    • a reference to the favorite list panel. The favorite tListbox will be dynamically create with this panel as it's parent

      Procedure c_favorite_path_list.handle_directory_listbox_drag_over(
          p_c_senderp_c_sourceTObjectp_xp_yInteger;
          p_drag_stateTDragStateVar pv_acceptBoolean);
        Begin
          pv_accept := p_c_senderp_c_source;
        End// handle_directory_listbox_drag_over

      Procedure c_favorite_path_list.handle_directory_listbox_drag_dop(
          p_c_senderp_c_sourceTObjectp_xp_yInteger);
        Var l_item_indexl_drop_indexInteger;
        Begin
          With m_c_list_box Do
          Begin
            l_drop_index:= ItemAtPos(Point(p_xp_y), True);
            If l_drop_index< 0
              Then l_drop_index:= 0;
            If l_drop_index>= Count
              Then l_drop_index:= Count- 1;
            // -- ItemIndex will be changed by the Exchange
            l_item_index:= ItemIndex;
            If l_drop_indexl_item_index
              Then Exit;

            Items.Exchange(ItemIndexl_drop_index);

            m_c_favorite_path_list.Exchange(l_item_indexl_drop_index);
          End// with m_c_list_box

          save_to_file;
        End// handle_directory_listbox_drag_dop



    and
    • m_c_favorite_path_list is the container, with the usual count, add, display routines
    • clicking on the favorite list selects the appropriate directory

      Procedure c_favorite_path_list.handle_favorite_listbox_click(p_c_sendertObject);
        Var l_c_favorite_pathc_favorite_path;
        Begin
          With m_c_list_box Do
            l_c_favorite_path:= f_c_find_by_favorite_path(Items[ItemIndex]);

          With l_c_favorite_path Do
            set_directory_listbox_directory(m_c_directory_listbox_refm_path);
        End// handle_favorite_listbox_click

    • clicking "-" removes the favorite item from the list

      Procedure c_favorite_path_list.handle_listbox_keypress(p_c_sendertObjectVar pv_keyChar);
        Var l_favorite_indexinteger;
        Begin
          If pv_key'-'
            Then Begin
                With m_c_list_box Do
                Begin
                  l_favorite_index:= ItemIndex;
                  Items.Delete(l_favorite_index);
                End;

                // -- remove from list
                f_c_delete_favorite_path(l_favorite_index).Free;

                save_to_file;
              End;
        End// handle_listbox_keypress

    • clicking "+" in the tDirectoryListbox adds another favorite item :

      Procedure c_favorite_path_list.handle_directory_listbox_keypress(
          p_c_sendertObjectVar pv_keyChar);
        Var l_path_namel_pathString;
            l_c_favorite_pathc_favorite_path;
            l_path_indexInteger;
            l_found_pathBoolean;
        Begin
          If pv_key'+'
            Then Begin
                l_path_name:= f_input_string(10, 10, 'enter path name'k_lettersk_digits+ ['_']);
                With m_c_directory_listbox_ref Do
                  l_path:= GetItemPath(ItemIndex)+ '\';

                With m_c_favorite_path_list Do
                Begin
                  l_found_path:= False;
                  For l_path_index:= 0 To Count- 1 Do
                    With f_c_favorite_path(l_path_indexDo
                      If SameText(l_pathm_path)
                        Then Begin
                            l_found_path:= True;
                            m_name:= l_path_name;
                            m_c_favorite_path_list[l_path_index]:= l_path_name;
                            m_c_list_box.Items[l_path_index]:= l_path_name;
                            Break;
                          End;

                  If Not l_found_path
                    Then Begin
                        l_c_favorite_path:= f_c_add_unique_favorite_path(l_path_namel_path'*');
                        With m_c_list_box.Items Do
                          AddObject(l_path_namel_c_favorite_path);
                      End;
                End// with m_c_favorite_path_list

                display_favorite_path_list;

                save_to_file;
              End;
        End// handle_directory_listbox_keypress

    • reordering the items is handled by drag and drop

      Procedure c_favorite_path_list.handle_directory_listbox_drag_over(
          p_c_senderp_c_sourceTObjectp_xp_yInteger;
          p_drag_stateTDragStateVar pv_acceptBoolean);
        Begin
          pv_accept := p_c_senderp_c_source;
        End// handle_directory_listbox_drag_over

      Procedure c_favorite_path_list.handle_directory_listbox_drag_dop(
          p_c_senderp_c_sourceTObjectp_xp_yInteger);
        Var l_item_indexl_drop_indexInteger;
        Begin
          With m_c_list_box Do
          Begin
            l_drop_index:= ItemAtPos(Point(p_xp_y), True);
            If l_drop_index< 0
              Then l_drop_index:= 0;
            If l_drop_index>= Count
              Then l_drop_index:= Count- 1;
            // -- ItemIndex will be changed by the Exchange
            l_item_index:= ItemIndex;
            If l_drop_indexl_item_index
              Then Exit;

            Items.Exchange(ItemIndexl_drop_index);

            m_c_favorite_path_list.Exchange(l_item_indexl_drop_index);
          End// with m_c_list_box

          save_to_file;
        End// handle_directory_listbox_drag_dop




Of course, much could be improved:
  • we could use Delphi generics instead of our own container
  • in our code, we directly created the tDirectoryListbox OnKeyDown event handlers. The user of this utility could not blindly use his own event handler. To solve then we should have overwritten the Click dispatcher.



4 - Download the Sources

Here are the source code files: The .ZIP file(s) contain:
  • the main program (.DPR, .DOF, .RES), the main form (.PAS, .DFM), and any other auxiliary form
  • any .TXT for parameters, samples, test data
  • all units (.PAS) for units
Those .ZIP
  • are self-contained: you will not need any other product (unless expressly mentioned).
  • for Delphi 6 projects, can be used from any folder (the pathes are RELATIVE)
  • will not modify your PC in any way beyond the path where you placed the .ZIP (no registry changes, no path creation etc).
To use the .ZIP:
  • create or select any folder of your choice
  • unzip the downloaded file
  • using Delphi, compile and execute
To remove the .ZIP simply delete the folder.

The Pascal code uses the Alsacian notation, which prefixes identifier by program area: K_onstant, T_ype, G_lobal, L_ocal, P_arametre, F_unction, C_lass etc. This notation is presented in the Alsacian Notation paper.



As usual:

  • please tell us at fcolibri@felix-colibri.com if you found some errors, mistakes, bugs, broken links or had some problem downloading the file. Resulting corrections will be helpful for other readers
  • we welcome any comment, criticism, enhancement, other sources or reference suggestion. Just send an e-mail to fcolibri@felix-colibri.com.
  • or more simply, enter your (anonymous or with your e-mail if you want an answer) comments below and clic the "send" button
    Name :
    E-mail :
    Comments * :
     

  • and if you liked this article, talk about this site to your fellow developpers, add a link to your links page ou mention our articles in your blog or newsgroup posts when relevant. That's the way we operate: the more traffic and Google references we get, the more articles we will write.

5 - The author

Felix John COLIBRI works at the Pascal Institute. Starting with Pascal in 1979, he then became involved with Object Oriented Programming, Delphi, Sql, Tcp/Ip, Html, UML. Currently, he is mainly active in the area of custom software development (new projects, maintenance, audits, BDE migration, Delphi Xe_n migrations, refactoring), Delphi Consulting and Delph training. His web site features tutorials, technical papers about programming with full downloadable source code, and the description and calendar of forthcoming Delphi, FireBird, Tcp/IP, Web Services, OOP  /  UML, Design Patterns, Unit Testing training sessions.
Created: sep-18. Last updated: feb-2020 - 105 articles, 240 .ZIP sources, 1295 figures
Contact : Felix COLIBRI - Phone: (33)1.42.83.69.36 / 06.87.88.23.91 - email:fcolibri@felix-colibri.com
Copyright © Felix J. Colibri   http://www.felix-colibri.com 2004 - 2020. All rigths reserved
Back:    Home  Papers  Training  Delphi developments  Links  Download
the Pascal Institute

Felix J COLIBRI

+ Home
  + articles_with_sources
    + database
    + web_internet_sockets
    + rest_services
    + oop_components
    + uml_design_patterns
    + debug_and_test
    + graphic
    + controls
    + colibri_utilities
      – delphi_net_bdsproj
      – dccil_bat_generator
      – coliget_search_engine
      – dfm_parser
      – dfm_binary_to_text
      – component_to_code
      – exe_dll_pe_explorer
      – dll_process_viewer
      – the_alsacian_notation
      – html_help_viewer
      – cooking_the_code
      – events_record_playback
      – colibri_hiragana_quiz
      – delphi_string_filter
      – directory_favorite_list
    + colibri_helpers
    + delphi
    + IDE
    + firemonkey
    + compilers
    + vcl
  + delphi_training
  + delphi_developments
  + sweet_home
  – download_zip_sources
  + links
Contacts
Site Map
– search :

RSS feed  
Blog