/////////////////////////////////////////////////////////////////////////////
// Name:        explorertreectrl.h
// Purpose:     wxExplorerTreeCtrl
// Author:      Julian Smart, Francesco Montorsi (extracted by configtool)
// Modified by:
// Created:     2006-11-28
// RCS-ID:      $Id: explorertreectrl.h,v 1.5 2007/01/14 15:08:44 frm Exp $
// Copyright:   (c) Julian Smart, Francesco Montorsi
// Licence:     wxWidgets license
/////////////////////////////////////////////////////////////////////////////


#ifndef _CHECKTREECTRL_H_
#define _CHECKTREECTRL_H_

#include "wx/treectrl.h"

// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------

enum wxExplorerTreeCtrlImageIndex
{
    wxETII_CLOSED_FOLDER,
    wxETII_OPEN_FOLDER,
    wxETII_CHECKED_BOX,
    wxETII_UNCHECKED_BOX
};


// ----------------------------------------------------------------------------
// wxExplorerTreeItemData
// ----------------------------------------------------------------------------

class wxExplorerTreeItemData : public wxTreeItemData
{
public:
    wxExplorerTreeItemData(size_t index) : m_index(index) {}

    size_t m_index;
};


// ----------------------------------------------------------------------------
// wxExplorerTreeCtrl
// ----------------------------------------------------------------------------

// wxSUNKEN_BORDER is required for GTK
#define wxETC_DEFAULT_STYLE     (wxTR_HAS_BUTTONS|wxSUNKEN_BORDER)

class wxExplorerTreeCtrl : public wxTreeCtrl
{
public:
    wxExplorerTreeCtrl(wxWindow* parent, wxWindowID id, 
                        const wxPoint& pos = wxDefaultPosition,
                        const wxSize& sz = wxDefaultSize, 
                        long style = wxETC_DEFAULT_STYLE)
    {
        Create(parent, id, pos, sz, style);
    }

    bool Create(wxWindow* parent, wxWindowID id, 
                const wxPoint& pos = wxDefaultPosition,
                const wxSize& sz = wxDefaultSize, 
                long style = wxETC_DEFAULT_STYLE);

    ~wxExplorerTreeCtrl();

public:     // public API

    // NOTE: this control sends events (as for almost all wx's controls)
    //       only on user changes. Not on function calls!

    void SetPath(const wxString &path);
    void RefreshContents();

    size_t GetFilesCount() const
        { return m_arrFiles.GetCount(); }

    const wxArrayString &GetFiles() const
        { return m_arrFiles; }
    const wxArrayInt &GetFileStatus() const
        { return m_arrFileStatus; }

    const wxArrayString &GetDirs() const
        { return m_arrDirs; }
    const wxArrayInt &GetDirStatus() const
        { return m_arrDirStatus; }

    // returns the path prefix which is part of the strings
    // returned by GetFiles() and GetDirs()
    wxString GetPathPrefix() const
        { return m_strPathPrefix; }

    wxArrayString GetFilesChecked(bool checked = true) const;
    wxArrayString GetDirsChecked(bool checked = true) const;

    // VERY IMPORTANT: GetDirsChecked(false) will return all the
    //                 folders not in "bold" status: i.e. all folders
    //                 which miss more than 1 file, not those which are
    //                 recursively unchecked!
    wxArrayString GetDirsRecursivelyUnChecked() const;

    void Check(const wxTreeItemId &item, bool check = true);
    void UnCheck(const wxTreeItemId &item)
        { Check(item, false); }

    void Toggle(const wxTreeItemId &item);

    void CheckAll(bool check = true)
        { Check(GetRootItem(), check); }
    void UnCheckAll()
        { Check(GetRootItem(), false); }

    wxString GetItemFullPath(const wxTreeItemId &item, 
                             wxPathFormat format = wxPATH_NATIVE) const;

    wxTreeItemId FindItem(const wxString &fullpath,
                          wxPathFormat format = wxPATH_NATIVE) const;

    wxExplorerTreeItemData* GetItemData(const wxTreeItemId& item) const
    {
        return wx_static_cast(wxExplorerTreeItemData*,
                              wxTreeCtrl::GetItemData(item));
    }


    // recursively test if the given tree item is checked
    // (for checked==true) or unchecked (for checked==false)
    bool IsChecked(const wxTreeItemId &item, bool checked = true) const;

    // returns true if the given tree item is a folder, false if a file.
    bool IsFolder(const wxTreeItemId &item) const;

public:     // event handlers    

    void OnKeyDown(wxKeyEvent& event);

    void OnTreeItemExpanded(wxTreeEvent& event);
    void OnTreeItemCollapsed(wxTreeEvent& event);
    void OnTreeItemMenu(wxTreeEvent& event);

    void OnMouseEvent(wxMouseEvent& event);
    void OnMenuContext(wxCommandEvent& event);

protected:      // helpers

    void LoadIcons();
    bool Traverse(const wxString &path, const wxTreeItemId &parent);

    wxTreeItemId DoFindItem(const wxTreeItemId &item,
                            const wxString &fullpath,
                            const wxChar sep) const;


    void DoGetDirsRecursivelyUnChecked(wxArrayString &ret,
                                        const wxTreeItemId &item,
                                        const wxString &prefix) const;

    void DoCheck(const wxTreeItemId &item, bool check);
    void UpdateParentStatus(const wxTreeItemId &item);

    bool RecursiveIsChecked(const wxTreeItemId &item, bool checked) const;

protected:

    bool m_bAlreadyWarned;
    wxString m_strCurrentPath, m_strPathPrefix;

    // the array of files & folders in this control:
    wxArrayString m_arrFiles, m_arrDirs;

    // m_arrFileStatus[i] is 1 if the file m_arrFiles[i] is checked
    wxArrayInt m_arrFileStatus, m_arrDirStatus;

    wxMenu *m_menuDirContext;
    wxMenu *m_menuFileContext;

    // only valid in OnMenuContext() event handler!
    wxTreeItemId m_currentItem;

private:
    DECLARE_CLASS(wxCheckTreeCtrl)
    DECLARE_EVENT_TABLE()
};



// ----------------------------------------------------------------------------
// wxExplorerTreeEvent
// ----------------------------------------------------------------------------

class wxExplorerTreeEvent : public wxTreeEvent
{
public:
    wxExplorerTreeEvent() {}
    wxExplorerTreeEvent(wxEventType eventType,
                        wxExplorerTreeCtrl *tree,
                        const wxTreeItemId &item,
                        bool check)
        : wxTreeEvent(eventType, tree, item)
    {
        m_bChecked = check;
    }

public:

    bool IsChecked() const
        { return m_bChecked; }

    // default copy ctor, assignment operator and dtor are ok
    virtual wxEvent *Clone() const { return new wxExplorerTreeEvent(*this); }

protected:

    bool m_bChecked;

private:
    DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxExplorerTreeEvent)
};

BEGIN_DECLARE_EVENT_TYPES()
    DECLARE_EVENT_TYPE(wxEVT_EXPLORER_TREE_CHECK, 5648)
END_DECLARE_EVENT_TYPES()

typedef void (wxEvtHandler::*wxExplorerTreeEventFunction)(wxExplorerTreeEvent&);

#define wxExplorerTreeEventHandler(func) \
    (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxExplorerTreeEventFunction, &func)

#define EVT_EXPLORER_TREE_CHECK(id, fn) \
    wx__DECLARE_EVT1(wxEVT_EXPLORER_TREE_CHECK, id, wxExplorerTreeEventHandler(fn))

#endif  // _CHECKTREECTRL_H_
