910e62b5创建于 1月15日历史提交
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_UI_OPERATIONS_HELPER_H_
#define CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_UI_OPERATIONS_HELPER_H_

#include <cstddef>

#include "base/memory/raw_ptr.h"
#include "components/bookmarks/browser/bookmark_node.h"
#include "components/bookmarks/common/bookmark_metrics.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"

class BookmarkMergedSurfaceService;
struct BookmarkParentFolder;
class Profile;
class Browser;

namespace bookmarks {
class BookmarkModel;
struct BookmarkNodeData;
}  // namespace bookmarks

namespace chrome {
enum class BookmarkReorderDropTarget;
}

namespace internal {

class BookmarkUIOperationsHelper {
 public:
  virtual ~BookmarkUIOperationsHelper();

  // Drops the bookmark nodes that are in `data` onto `target_parent()` at
  // `index`.
  // `copy` indicates the source operation: if true then the bookmarks in
  // `data` are copied, otherwise they are moved if they belong to the same
  // profile.
  // `browser` is needed if the user should be asked to confirm whether they
  // want to move a bookmark between local and account storage. Returns the drop
  // type used.
  ui::mojom::DragOperation DropBookmarks(
      Profile* profile,
      const bookmarks::BookmarkNodeData& data,
      size_t index,
      bool copy,
      chrome::BookmarkReorderDropTarget target,
      Browser* browser = nullptr);

  // Copies nodes onto the clipboard. The nodes are copied in such a way that if
  // pasted again new nodes can be created. Pass the calling context through as
  // `source`.
  static void CopyToClipboard(
      bookmarks::BookmarkModel* model,
      const std::vector<
          raw_ptr<const bookmarks::BookmarkNode, VectorExperimental>>& nodes,
      bookmarks::metrics::BookmarkEditSource source,
      bool is_off_the_record);

  // Copies nodes onto the clipboard then removes them from the bookmark model.
  // Pass the calling context through as `source`.
  static void CutToClipboard(
      bookmarks::BookmarkModel* model,
      const std::vector<
          raw_ptr<const bookmarks::BookmarkNode, VectorExperimental>>& nodes,
      bookmarks::metrics::BookmarkEditSource source,
      bool is_off_the_record);

  // Returns true if the user can paste from the clipboard a bookmark url/node
  // into `target_parent()`.
  bool CanPasteFromClipboard() const;

  // Pastes from the clipboard. The new nodes are added to `target_parent()`.
  // The nodes are inserted at `index`.
  void PasteFromClipboard(size_t index);

 protected:
  // Represents the target parent node for the operation.
  // For non-merged surfaces, it's a bookmark node.
  // For merged surfaces, it's either a bookmark node or a permanent folder.
  class TargetParent {
   public:
    virtual ~TargetParent();
    virtual bool IsManaged() const = 0;
    virtual bool IsPermanentNode() const = 0;
    virtual bool IsDirectChild(const bookmarks::BookmarkNode* node) const = 0;
    virtual bookmarks::BookmarkNode::Type GetType() const = 0;
    virtual const bookmarks::BookmarkNode* GetNodeAtIndex(
        size_t index) const = 0;
    virtual size_t GetChildrenCount() const = 0;
  };

  virtual bookmarks::BookmarkModel* model() = 0;
  virtual void AddNodesAsCopiesOfNodeData(
      const bookmarks::BookmarkNodeData& data,
      size_t index_to_add_at) = 0;
  virtual void MoveBookmarkNodeData(const bookmarks::BookmarkNodeData& data,
                                    const base::FilePath& profile_path,
                                    size_t index_to_add_at,
                                    Browser* browser) = 0;
  virtual const TargetParent* target_parent() const = 0;

 private:
  static void CopyOrCutToClipboard(
      bookmarks::BookmarkModel* model,
      const std::vector<
          raw_ptr<const bookmarks::BookmarkNode, VectorExperimental>>& nodes,
      bool remove_nodes,
      bookmarks::metrics::BookmarkEditSource source,
      bool is_off_the_record);

  // Updates `title` such that `url` and `title` pair are unique among the
  // children of `target_parent()`.
  void MakeTitleUnique(const GURL& url, std::u16string* title) const;
};

}  // namespace internal

// Helper class for UI operations e.g. Drop, Copy, Paste bookmarks.
//  `BookmarkUIOperationsHelperNonMergedSurfaces` must be used in non bookmark
//  merged surfaces where there is a clear distinction between account and local
//  bookmarks.
class BookmarkUIOperationsHelperNonMergedSurfaces
    : public internal::BookmarkUIOperationsHelper {
 public:
  // `model` and `parent` must be not null and outlive `this`.
  // `parent` is the parent node where nodes are being dropped, copy/cut ->
  // paste into parent folder.
  BookmarkUIOperationsHelperNonMergedSurfaces(
      bookmarks::BookmarkModel* model,
      const bookmarks::BookmarkNode* parent);

  BookmarkUIOperationsHelperNonMergedSurfaces(
      const BookmarkUIOperationsHelperNonMergedSurfaces&) = delete;
  BookmarkUIOperationsHelperNonMergedSurfaces& operator=(
      const BookmarkUIOperationsHelperNonMergedSurfaces&) = delete;

  ~BookmarkUIOperationsHelperNonMergedSurfaces() override;

 protected:
  bookmarks::BookmarkModel* model() override;
  void AddNodesAsCopiesOfNodeData(const bookmarks::BookmarkNodeData& data,
                                  size_t index_to_add_at) override;
  void MoveBookmarkNodeData(const bookmarks::BookmarkNodeData& data,
                            const base::FilePath& profile_path,
                            size_t index_to_add_at,
                            Browser* browser) override;
  const internal::BookmarkUIOperationsHelper::TargetParent* target_parent()
      const override;

 private:
  class TargetParent
      : public internal::BookmarkUIOperationsHelper::TargetParent {
   public:
    static std::unique_ptr<TargetParent> CreateTargetParent(
        bookmarks::BookmarkModel* model,
        const bookmarks::BookmarkNode* parent);

    TargetParent(const bookmarks::BookmarkNode* parent, bool is_managed);
    ~TargetParent() override;

    const bookmarks::BookmarkNode* parent_node() const;

    // internal::BookmarkUIOperationsHelper::TargetParent
    bool IsManaged() const override;
    bool IsPermanentNode() const override;
    bool IsDirectChild(const bookmarks::BookmarkNode* node) const override;
    bookmarks::BookmarkNode::Type GetType() const override;
    const bookmarks::BookmarkNode* GetNodeAtIndex(size_t index) const override;
    size_t GetChildrenCount() const override;

   private:
    const raw_ptr<const bookmarks::BookmarkNode> parent_;
    const bool is_managed_;
  };

  const bookmarks::BookmarkNode* parent_node() const;

  const raw_ptr<bookmarks::BookmarkModel> model_;
  const std::unique_ptr<TargetParent> target_parent_;
};

// Helper class for UI operations e.g. Drop, Copy, Paste bookmarks.
//  `BookmarkUIOperationsHelperNonMergedSurfaces` must be used in bookmark
//  merged surfaces (Bookmark bar, bookmark menu and side panel).
class BookmarkUIOperationsHelperMergedSurfaces
    : public internal::BookmarkUIOperationsHelper {
 public:
  BookmarkUIOperationsHelperMergedSurfaces(
      BookmarkMergedSurfaceService* merged_surface_service,
      const BookmarkParentFolder* parent);

  BookmarkUIOperationsHelperMergedSurfaces(
      const BookmarkUIOperationsHelperMergedSurfaces&) = delete;
  BookmarkUIOperationsHelperMergedSurfaces& operator=(
      const BookmarkUIOperationsHelperMergedSurfaces&) = delete;

  ~BookmarkUIOperationsHelperMergedSurfaces() override;

  // Merged bookmark surfaces can trigger a non-merged bookmark UI e.g. bookmark
  // context menu can trigger the edit bookmark UI or the bookmark manager with
  // a choice of a highlighted node.
  // This function returns the default parent to use for non-merged surfaces UIs
  // triggered from merged surfaces.
  // This function treats managed nodes as some operations are allowed; e.g.
  // opening the bookmark manager with a managed node highlighted. This should
  // not be used by managed folders if intended to be used for adding new nodes,
  // since managed bookmarks do not support creating nodes.
  const bookmarks::BookmarkNode* GetDefaultParentForNonMergedSurfaces() const;

 protected:
  bookmarks::BookmarkModel* model() override;
  void AddNodesAsCopiesOfNodeData(const bookmarks::BookmarkNodeData& data,
                                  size_t index_to_add_at) override;
  void MoveBookmarkNodeData(const bookmarks::BookmarkNodeData& data,
                            const base::FilePath& profile_path,
                            size_t index_to_add_at,
                            Browser* browser) override;
  const internal::BookmarkUIOperationsHelper::TargetParent* target_parent()
      const override;

 private:
  class TargetParent
      : public internal::BookmarkUIOperationsHelper::TargetParent {
   public:
    static std::unique_ptr<TargetParent> CreateTargetParent(
        BookmarkMergedSurfaceService* merged_surface_service,
        const BookmarkParentFolder* parent);

    TargetParent(BookmarkMergedSurfaceService* merged_surface_service,
                 const BookmarkParentFolder* parent);
    ~TargetParent() override;

    const BookmarkParentFolder* parent_folder() const;

    // internal::BookmarkUIOperationsHelper::TargetParent
    bool IsManaged() const override;
    bool IsPermanentNode() const override;
    bool IsDirectChild(const bookmarks::BookmarkNode* node) const override;
    bookmarks::BookmarkNode::Type GetType() const override;
    const bookmarks::BookmarkNode* GetNodeAtIndex(size_t index) const override;
    size_t GetChildrenCount() const override;

   private:
    const raw_ptr<BookmarkMergedSurfaceService> merged_surface_service_;
    const raw_ptr<const BookmarkParentFolder> parent_;
  };

  const BookmarkParentFolder* parent_folder() const;

  const raw_ptr<BookmarkMergedSurfaceService> merged_surface_service_;
  const std::unique_ptr<TargetParent> target_parent_;
};

#endif  // CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_UI_OPERATIONS_HELPER_H_