text: #ifndef VDIRECTORYTREE_H
  #define VDIRECTORYTREE_H
  
  #include <QJsonObject>
  #include <QPointer>
  #include <QVector>
  #include <QMap>
  #include <QList>
  #include <QHash>
  
  #include "vtreewidget.h"
  #include "vdirectory.h"
  #include "vnotebook.h"
  #include "vnavigationmode.h"
  #include "vconstants.h"
  
  class VEditArea;
  class QLabel;
  
  class VDirectoryTree : public VTreeWidget, public VNavigationMode
  {
      Q_OBJECT
  public:
      explicit VDirectoryTree(QWidget *parent = 0);
  
      void setEditArea(VEditArea *p_editArea);
  
      // Locate to the item representing @p_directory.
      bool locateDirectory(const VDirectory *p_directory);
  
      const VNotebook *currentNotebook() const;
  
      VDirectory *currentDirectory() const;
  
      // Implementations for VNavigationMode.
      void showNavigation() Q_DECL_OVERRIDE;
      bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;
  
  signals:
      void currentDirectoryChanged(VDirectory *p_directory);
  
      void directoryUpdated(const VDirectory *p_directory, UpdateAction p_act);
  
  public slots:
      // Set directory tree to display a given notebook @p_notebook.
      void setNotebook(VNotebook *p_notebook);
  
      // Create a root folder.
      void newRootDirectory();
  
      // View and edit info about directory.
      void editDirectoryInfo();
  
      // Clear and re-build the whole directory tree.
      // Do not load all the sub-directories at once.
      void updateDirectoryTree();
  
  private slots:
      // Set the state of expansion of the directory.
      void handleItemExpanded(QTreeWidgetItem *p_item);
  
      // Set the state of expansion of the directory.
      void handleItemCollapsed(QTreeWidgetItem *p_item);
  
      void contextMenuRequested(QPoint pos);
  
      // Directory selected folder.
      // Currently only support single selected item.
      void deleteSelectedDirectory();
  
      // Create sub-directory of current item's directory.
      void newSubDirectory();
  
      // Current tree item changed.
      void currentDirectoryItemChanged(QTreeWidgetItem *currentItem);
  
      // Copy selected directories.
      // Will put a Json string into the clipboard which contains the information
      // about copied directories.
      void copySelectedDirectories(bool p_isCut = false);
  
      void cutSelectedDirectories();
  
      // Paste directories from clipboard as sub-directories of current item.
      void pasteDirectoriesFromClipboard();
  
      // Open the folder's parent directory in system's file browser.
      void openDirectoryLocation() const;
  
      // Reload the content of current directory.
      void reloadFromDisk();
  
      // Sort sub-folders of current item's folder.
      void sortItems();
  
      // Pin selected directory to History.
      void pinDirectoryToHistory();
  
  protected:
      void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
  
      void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
  
  private:
      // Build the subtree of @p_parent recursively to the depth @p_depth.
      // @p_depth: negative - infinite levels.
      // Will expand the item if the corresponding directory was expanded before.
      // Will treat items with children as items having been built before.
      void buildSubTree(QTreeWidgetItem *p_parent, int p_depth);
  
      // Fill the content of a tree item according to @p_directory.
      void fillTreeItem(QTreeWidgetItem *p_item, VDirectory *p_directory);
  
      void initShortcuts();
  
      // Update @p_item's direct children only: deleted, added, renamed.
      void updateItemDirectChildren(QTreeWidgetItem *p_item);
  
      // Find the corresponding item of @p_dir;
      // Return's NULL if no item is found and it is the root directory if @p_widget is true.
      QTreeWidgetItem *findVDirectory(const VDirectory *p_dir, bool *p_widget = NULL);
  
      QPointer<VDirectory> getVDirectory(QTreeWidgetItem *p_item) const;
  
      // Paste @p_dirs as sub-directory of @p_destDir.
      void pasteDirectories(VDirectory *p_destDir,
                            const QVector<QString> &p_dirs,
                            bool p_isCut);
  
      // Build the subtree of @p_item's children if it has not been built yet.
      // We need to fill the children before showing a item to get a correct render.
      void buildChildren(QTreeWidgetItem *p_item);
  
      // Expand/create the directory tree nodes to @p_directory.
      QTreeWidgetItem *expandToVDirectory(const VDirectory *p_directory);
  
      // Expand the currently-built subtree of @p_item according to VDirectory.isExpanded().
      void expandSubTree(QTreeWidgetItem *p_item);
  
      // We use a map to save and restore current directory of each notebook.
      // Try to restore current directory after changing notebook.
      // Return false if no cache item found for current notebook.
      bool restoreCurrentItem();
  
      // Generate new magic to m_magicForClipboard.
      int getNewMagic();
  
      // Check if @p_magic equals to m_magicForClipboard.
      bool checkMagic(int p_magic) const;
  
      // Check if clipboard contains valid info to paste as directories.
      bool pasteAvailable() const;
  
      // Sort sub-directories of @p_dir.
      void sortItems(VDirectory *p_dir);
  
      QPointer<VNotebook> m_notebook;
  
      VEditArea *m_editArea;
  
      // Each notebook's current item's VDirectory.
      QHash<VNotebook *, VDirectory *> m_notebookCurrentDirMap;
  
      // Magic number for clipboard operations.
      int m_magicForClipboard;
  };
  
  inline QPointer<VDirectory> VDirectoryTree::getVDirectory(QTreeWidgetItem *p_item) const
  {
      Q_ASSERT(p_item);
      return p_item->data(0, Qt::UserRole).value<VDirectory *>();
  }
  
  inline void VDirectoryTree::setEditArea(VEditArea *p_editArea)
  {
      m_editArea = p_editArea;
  }
  
  inline const VNotebook *VDirectoryTree::currentNotebook() const
  {
      return m_notebook;
  }
  
  #endif // VDIRECTORYTREE_H
  