1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_CLIPBOARD_CLIPBOARD_HISTORY_H_
#define ASH_CLIPBOARD_CLIPBOARD_HISTORY_H_
#include <deque>
#include <list>
#include "ash/ash_export.h"
#include "ash/clipboard/clipboard_history_item.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/token.h"
#include "ui/base/clipboard/clipboard_data.h"
#include "ui/base/clipboard/clipboard_observer.h"
namespace ash {
class ScopedClipboardHistoryPauseImpl;
namespace clipboard_history_util {
enum class PauseBehavior;
} // namespace clipboard_history_util
// Keeps track of the last few things saved in the clipboard.
class ASH_EXPORT ClipboardHistory : public ui::ClipboardObserver {
public:
class ASH_EXPORT Observer : public base::CheckedObserver {
public:
// Called when a `ClipboardHistoryItem` has been added. `is_duplicate` is
// true if `item` is already in clipboard history when adding.
virtual void OnClipboardHistoryItemAdded(const ClipboardHistoryItem& item,
bool is_duplicate) {}
// Called when a ClipboardHistoryItem has been removed.
virtual void OnClipboardHistoryItemRemoved(
const ClipboardHistoryItem& item) {}
// Called when ClipboardHistory is Clear()-ed.
virtual void OnClipboardHistoryCleared() {}
// Called when the operation on clipboard data is confirmed.
virtual void OnOperationConfirmed(bool copy) {}
};
ClipboardHistory();
ClipboardHistory(const ClipboardHistory&) = delete;
ClipboardHistory& operator=(const ClipboardHistory&) = delete;
~ClipboardHistory() override;
void AddObserver(Observer* observer) const;
void RemoveObserver(Observer* observer) const;
// Returns the list of most recent items. The returned list is sorted by
// recency.
const std::list<ClipboardHistoryItem>& GetItems() const;
std::list<ClipboardHistoryItem>& GetItems();
// Deletes every item in the clipboard history. The clipboard is cleared as
// well to ensure that its contents stay in sync with the first item in the
// clipboard history.
void Clear();
// Returns whether the clipboard history of the active account is empty.
bool IsEmpty() const;
// Remove the item specified by `id`. If the target item does not exist,
// do nothing.
void RemoveItemForId(const base::UnguessableToken& id);
// ui::ClipboardObserver:
void OnClipboardDataChanged() override;
void OnClipboardDataRead() override;
base::WeakPtr<ClipboardHistory> GetWeakPtr();
private:
// Friended to allow `ScopedClipboardHistoryPauseImpl` to `Pause()` and
// `Resume()`.
// TODO(b/269470292): Use a `PassKey` for this.
friend class ScopedClipboardHistoryPauseImpl;
// Ensures that the clipboard buffer contains the same data as the item at the
// top of clipboard history. If clipboard history is empty, then the clipboard
// is cleared.
void SyncClipboardToClipboardHistory();
// Adds `data` to the top of the history list if `data` is supported by
// clipboard history. If `data` is not supported, this method no-ops. If
// `data` is already in the history list, `data` will be moved to the top of
// the list.
void MaybeCommitData(ui::ClipboardData data, bool is_reorder_on_paste);
// When `Pause()` is called, clipboard accesses will modify clipboard history
// according to `pause_behavior` until `Resume()` is called with that pause's
// `pause_id`. If `Pause()` is called while another pause is active, the
// newest pause's behavior will be respected. When the newest pause ends, the
// next newest pause's behavior will be restored.
const base::Token& Pause(
clipboard_history_util::PauseBehavior pause_behavior);
void Resume(const base::Token& pause_id);
struct PauseInfo {
base::Token pause_id;
clipboard_history_util::PauseBehavior pause_behavior;
};
// Keeps track of consecutive clipboard operations and records metrics.
void OnClipboardOperation(bool copy);
// Active clipboard history pauses, stored in LIFO order so that the newest
// pause dictates behavior. Rather than a stack, we use a deque where the
// newest pause is added to and removed from the front. Not using a stack
// allows us to find and remove the correct pause in cases where pauses are
// not destroyed in LIFO order, and adding to the front of the deque rather
// than the back allows us to iterate forward when searching for the correct
// pause, simplifying removal logic.
std::deque<PauseInfo> pauses_;
// The number of consecutive copies, reset after a paste.
int consecutive_copies_ = 0;
// The number of consecutive pastes, reset after a copy.
int consecutive_pastes_ = 0;
// The history of data copied to the Clipboard. Items of the list are sorted
// by recency.
std::list<ClipboardHistoryItem> history_list_;
// Mutable to allow adding/removing from |observers_| through a const
// ClipboardHistory.
mutable base::ObserverList<Observer> observers_;
// Factory to create WeakPtrs used to debounce calls to `CommitData()`.
base::WeakPtrFactory<ClipboardHistory> commit_data_weak_factory_{this};
// Factory to create WeakPtrs used to debounce calls to
// `OnClipboardOperation()`.
base::WeakPtrFactory<ClipboardHistory> clipboard_histogram_weak_factory_{
this};
// Factory to create WeakPtrs for ClipboardHistory.
base::WeakPtrFactory<ClipboardHistory> weak_factory_{this};
};
} // namespace ash
#endif // ASH_CLIPBOARD_CLIPBOARD_HISTORY_H_
|