C++程序  |  211行  |  6.92 KB

// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_GTK_GTK_TREE_H_
#define CHROME_BROWSER_UI_GTK_GTK_TREE_H_
#pragma once

#include <gtk/gtk.h>
#include <set>
#include <vector>

#include "base/basictypes.h"
#include "chrome/browser/remove_rows_table_model.h"
#include "ui/base/models/table_model_observer.h"
#include "ui/base/models/tree_model.h"

namespace ui {
class TableModel;
}

namespace gtk_tree {

// Get the row number corresponding to |path|.
gint GetRowNumForPath(GtkTreePath* path);

// Get the row number corresponding to |iter|.
gint GetRowNumForIter(GtkTreeModel* model, GtkTreeIter* iter);

// Get the row number in the child tree model corresponding to |sort_path| in
// the parent tree model.
gint GetTreeSortChildRowNumForPath(GtkTreeModel* sort_model,
                                   GtkTreePath* sort_path);

// Select the given row by number.
void SelectAndFocusRowNum(int row, GtkTreeView* tree_view);

// Remove the row and all its children from the |tree_store|.  If there is a
// following row, |iter| will be updated to point to the it and the return value
// will be true, otherwise the return will be false and |iter| is no longer
// valid.
bool RemoveRecursively(GtkTreeStore* tree_store, GtkTreeIter* iter);

// Writes all the indexes of selected rows into |out|.
void GetSelectedIndices(GtkTreeSelection* selection, std::set<int>* out);

// A helper class for populating a GtkListStore from a ui::TableModel.
class TableAdapter : public ui::TableModelObserver {
 public:

  enum ColumnID {
    COL_TITLE = 0,
    COL_IS_HEADER,
    COL_IS_SEPARATOR,
    COL_GROUP_ID,
    COL_WEIGHT,
    COL_WEIGHT_SET,
    COL_LAST_ID
  };

  class Delegate {
   public:
    // Should fill in the column and row.
    virtual void SetColumnValues(int row, GtkTreeIter* iter) = 0;

    // Called after any change to the ui::TableModel but before the
    // corresponding change to the GtkListStore.
    virtual void OnAnyModelUpdateStart() {}

    // Called after any change to the ui::TableModel.
    virtual void OnAnyModelUpdate() {}

    // When the ui::TableModel has been completely changed, called by
    // OnModelChanged after clearing the list store.  Can be overridden by the
    // delegate if it needs to do extra initialization before the list store is
    // populated.
    virtual void OnModelChanged() {}

   protected:
    virtual ~Delegate() {}
  };

  // |table_model| may be NULL.
  TableAdapter(Delegate* delegate,
               GtkListStore* list_store,
               ui::TableModel* table_model);
  virtual ~TableAdapter() {}

  // Replace the ui::TableModel with a different one.  If the list store
  // currently has items this would cause weirdness, so this should generally
  // only be called during the Delegate's OnModelChanged call, or if the adapter
  // was created with a NULL |table_model|.
  void SetModel(ui::TableModel* table_model);

  // Add all model rows corresponding to the given list store indices to |rows|.
  void MapListStoreIndicesToModelRows(const std::set<int>& list_store_indices,
                                      RemoveRowsTableModel::Rows* model_rows);

  // GtkTreeModel callbacks:
  // Callback checking whether a row should be drawn as a separator.
  static gboolean OnCheckRowIsSeparator(GtkTreeModel* model,
                                        GtkTreeIter* iter,
                                        gpointer user_data);

  // Callback checking whether a row may be selected.  We use some rows in the
  // table as headers/separators for the groups, which should not be selectable.
  static gboolean OnSelectionFilter(GtkTreeSelection* selection,
                                    GtkTreeModel* model,
                                    GtkTreePath* path,
                                    gboolean path_currently_selected,
                                    gpointer user_data);

  // ui::TableModelObserver implementation.
  virtual void OnModelChanged();
  virtual void OnItemsChanged(int start, int length);
  virtual void OnItemsAdded(int start, int length);
  virtual void OnItemsRemoved(int start, int length);

 private:
  // Return whether the row pointed to by |iter| is a group row, i.e. a group
  // header, or a separator.
  bool IsGroupRow(GtkTreeIter* iter) const;

  // Return the index into the list store for the given model row.
  int GetListStoreIndexForModelRow(int model_row) const;

  // Add the values from |row| of the ui::TableModel.
  void AddNodeToList(int row);

  Delegate* delegate_;
  GtkListStore* list_store_;
  ui::TableModel* table_model_;

  DISALLOW_COPY_AND_ASSIGN(TableAdapter);
};

// A helper class for populating a GtkTreeStore from a TreeModel.
// TODO(mattm): support SetRootShown(true)
class TreeAdapter : public ui::TreeModelObserver {
 public:
  // Column ids for |tree_store_|.
  enum {
    COL_ICON,
    COL_TITLE,
    COL_NODE_PTR,
    COL_COUNT,
  };

  class Delegate {
   public:
    // Called after any change to the TreeModel but before the corresponding
    // change to the GtkTreeStore.
    virtual void OnAnyModelUpdateStart() {}

    // Called after any change to the GtkTreeStore.
    virtual void OnAnyModelUpdate() {}

   protected:
    virtual ~Delegate() {}
  };

  TreeAdapter(Delegate* delegate, ui::TreeModel* tree_model);
  virtual ~TreeAdapter();

  // Populate the tree store from the |tree_model_|.
  void Init();

  // Return the tree store.
  GtkTreeStore* tree_store() { return tree_store_; }

  // Get the TreeModelNode corresponding to iter in the tree store.
  ui::TreeModelNode* GetNode(GtkTreeIter* iter);

  // Begin TreeModelObserver implementation.
  virtual void TreeNodesAdded(ui::TreeModel* model,
                              ui::TreeModelNode* parent,
                              int start,
                              int count);
  virtual void TreeNodesRemoved(ui::TreeModel* model,
                                ui::TreeModelNode* parent,
                                int start,
                                int count);
  virtual void TreeNodeChanged(ui::TreeModel* model, ui::TreeModelNode* node);
  // End TreeModelObserver implementation.

 private:
  // Fill the tree store values for a given node.
  void FillRow(GtkTreeIter* iter, ui::TreeModelNode* node);

  // Fill the tree store for a row and all its descendants.
  void Fill(GtkTreeIter* parent_iter, ui::TreeModelNode* parent_node);

  // Get the GtkTreePath in the tree store for the given node.
  // The returned path should be freed with gtk_tree_path_free.
  GtkTreePath* GetTreePath(ui::TreeModelNode* node);

  // Get the GtkTreeIter in the tree store for the given node.
  bool GetTreeIter(ui::TreeModelNode* node, GtkTreeIter* iter);

  Delegate* delegate_;
  GtkTreeStore* tree_store_;
  ui::TreeModel* tree_model_;
  std::vector<GdkPixbuf*> pixbufs_;

  DISALLOW_COPY_AND_ASSIGN(TreeAdapter);
};

}  // namespace gtk_tree

#endif  // CHROME_BROWSER_UI_GTK_GTK_TREE_H_