Click here to Skip to main content
15,892,809 members
Articles / Desktop Programming / Windows Forms

FileSelect - Hassle Free Implementation of the File Menu

Rate me:
Please Sign up or sign in to vote.
4.67/5 (15 votes)
4 May 2009CPOL13 min read 51.4K   512   39  
A WinForms user control that implements the details of file handling commands for any document-centric application
// ==================================================================
// 
//  FileSelect - RecentFileList.cs
// 
//  Copyright 2009 Peter Hauptmann
//  This code is published under CodeProject Open License 
//    see http://www.codeproject.com/info/cpol10.aspx
//  Latest version and feedback at
//   http://www.codeproject.com/KB/menus/fileselect.aspx 
// 
// ------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel;

namespace PH.UI.FileSelect
{

  /// <summary>Implements an LRU list of file names.</summary>
  public class RecentFileList : Component
  {
    private int m_persistCount = 10;

    /// <summary>Number of files to remember in the <see cref="AllFiles"/> list.</summary>
    /// <remarks>This may be more files than will be displayed, which is controlled by the 
    /// <see cref="ListCount"/> property. This improves user interface behavior when 
    /// the <c>ListCount</c> property changes, but might also be seen as a potential privacy 
    /// leak in critical applications (storing more data than the user sees).</remarks>
    [Category("Behavior")]
    [DefaultValue(10)]
    [Description("number of items that will be remembered in the settings.")]
    public int PersistCount
    {
      get { return Math.Max(m_persistCount, m_listCount); }
      set
      {
        m_persistCount = value;
        RemoveExcessFiles();
      }
    }

    private void RemoveExcessFiles()
    {
      int want = PersistCount;
      if (want < 0)
        want = 0;

      if (want < m_files.Count)
        m_files.RemoveRange(want, m_files.Count - want);
    }

    /// <summary>Number of files to display in the recent file list.</summary>
    /// <remarks>see also <see cref="PersistCount"/></remarks>
    [Category("Behavior")]
    [DefaultValue(4)]
    [Description("number of items that will be shown in the recent file list.")]
    private int m_listCount = 4;
    public int ListCount
    {
      get { return m_listCount; }
      set
      {
        m_listCount = value;
        OnFileListChanged();
      }
    }

    private List<string> m_files = new List<string>();

    /// <summary>number of files in the list, up to <c>ListCount</c>.</summary>
    [Browsable(false)]
    public int Count
    {
      get { return Math.Min(m_files.Count, m_listCount); }
    }

    /// <summary>list of files, up to <see cref="ListCount"/></summary>
    [Browsable(false)]
    public IEnumerable<string> Files
    {
      get
      {
        for (int i = 0; i < Math.Min(m_files.Count, m_listCount); ++i)
          yield return m_files[i];
      }
    }

    /// <summary>clears the recent files list.</summary>
    public void Clear()
    {
      m_files.Clear();
      OnFileListChanged();
    }

    /// <summary>function used to clean up file names.</summary>
    public static string CanonicalName(string file)
    {
      file = Path.GetFullPath(file);
      // file = Path.Canonicalize(path);
      return file;
    }

    /// <summary>adds a file on top of the list.</summary>
    public void Add(string file)
    {
      file = CanonicalName(file);
      int existingIdx = m_files.IndexOf(file);

      if (existingIdx > 0)
        m_files.RemoveAt(existingIdx);

      if (existingIdx != 0)
        m_files.Insert(0, file);

      RemoveExcessFiles();

      OnFileListChanged();
    }

    /// <summary>Index of the file in the list</summary>
    /// <remarks>search includes the files up to <see cref="PersistCount"/>.</remarks>
    /// <param name="file">file to find</param>
    /// <returns>index of the file in the list, or -1 if not found.</returns>
    public int IndexOf(string file)
    {
      file = CanonicalName(file);
      return m_files.IndexOf(file);
    }

    /// <summary>removes the specified file from the list.</summary>
    public void Remove(string file)
    {
      file = CanonicalName(file);
      int idx = m_files.IndexOf(file);
      if (idx >= 0)
      {
        OnFileListChanged();
        m_files.RemoveAt(idx);
      }
    }

    /// <summary>removes the file at the given index.</summary>
    public void RemoveAt(int idx)
    {
      m_files.RemoveAt(idx);
      OnFileListChanged();
    }

    /// <summary>fires when the list of files has changed.</summary>
    public event EventHandler FileListChanged;
    protected virtual void OnFileListChanged()
    {
      if (FileListChanged != null)
        FileListChanged(this, EventArgs.Empty);
    }

    /// <summary>a string property holding all file names, intended for application settings.</summary>
    /// <remarks>You can persist this property in the user settings to remember his list of recent files.</remarks>
    [Browsable(false)]
    public string AllFiles
    {
      get 
      {
        string all = null;
        foreach(string s in m_files)
        {
          if (all == null)
            all = s;
          else
            all = all + "\n" + s;
        }
        return all;
      }
      set
      {
        m_files.Clear();
        string[] files = (value??String.Empty).Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
        m_files.AddRange(files);
        OnFileListChanged();
      }

    }


  }

  /// <summary>adds additional designer properties to them</summary>
  public class RecentFiles : RecentFileList
  {

    [Browsable(false)]
    public event EventHandler DisplaySettingsChanged;


    private bool m_bAddShortcuts = true;
    [Category("Display")]
    [DefaultValue(true)]
    [Description("Add Numbers as shortcuts to recent file lists")]
    public bool AddShortcuts
    {
      get { return m_bAddShortcuts; }
      set 
      { 
        if (m_bAddShortcuts != value)
        {
          m_bAddShortcuts = value;
          FireDisplaySettingsChanged();
        }
      }
    }

    private int m_displayPathLength = 40;

    [Category("Display")]
    [DefaultValue(40)]
    [Description("Shorten file names in recent file list to N characters. -1 to not shorten names.")]
    public int DisplayPathLength
    {
      get { return m_displayPathLength; }
      set
      {
        if (value >= 0 && value < 10)
          value = 10;
        else if (value < -1)
          value = -1;

        if (value != m_displayPathLength)
        {
          m_displayPathLength = value;
          FireDisplaySettingsChanged();
        }
      }
    }


    private void FireDisplaySettingsChanged()
    {
      if (DisplaySettingsChanged != null)
        DisplaySettingsChanged(this, EventArgs.Empty);
    }
    
  }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Klippel
Germany Germany
Peter is tired of being called "Mr. Chen", even so certain individuals insist on it. No, he's not chinese.

Peter has seen lots of boxes you youngsters wouldn't even accept as calculators. He is proud of having visited the insides of a 16 Bit Machine.

In his spare time he ponders new ways of turning groceries into biohazards, or tries to coax South American officials to add some stamps to his passport.

Beyond these trivialities Peter works for Klippel[^], a small german company that wants to make mankind happier by selling them novel loudspeaker measurement equipment.


Where are you from?[^]



Please, if you are using one of my articles for anything, just leave me a comment. Seeing that this stuff is actually useful to someone is what keeps me posting and updating them.
Should you happen to not like it, tell me, too

Comments and Discussions