1 /*
2 Copyright (c) 2020, Lukas Holecek <hluk@email.cz>
3
4 This file is part of CopyQ.
5
6 CopyQ is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 CopyQ is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with CopyQ. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "clipboardbrowserplaceholder.h"
21
22 #include "common/common.h"
23 #include "common/log.h"
24 #include "common/timer.h"
25 #include "item/itemstore.h"
26 #include "gui/clipboardbrowser.h"
27 #include "gui/iconfactory.h"
28 #include "gui/icons.h"
29
30 #include <QPushButton>
31 #include <QVBoxLayout>
32 #include <QWidget>
33
34 #include <memory>
35
ClipboardBrowserPlaceholder(const QString & tabName,const ClipboardBrowserSharedPtr & shared,QWidget * parent)36 ClipboardBrowserPlaceholder::ClipboardBrowserPlaceholder(
37 const QString &tabName, const ClipboardBrowserSharedPtr &shared, QWidget *parent)
38 : QWidget(parent)
39 , m_tabName(tabName)
40 , m_sharedData(shared)
41 {
42 auto layout = new QVBoxLayout(this);
43 layout->setContentsMargins(0, 0, 0, 0);
44
45 initSingleShotTimer( &m_timerExpire, 0, this, &ClipboardBrowserPlaceholder::expire );
46 }
47
createBrowser()48 ClipboardBrowser *ClipboardBrowserPlaceholder::createBrowser()
49 {
50 if (m_browser)
51 return m_browser;
52
53 if (m_loadButton)
54 return nullptr;
55
56 std::unique_ptr<ClipboardBrowser> c( new ClipboardBrowser(m_tabName, m_sharedData, this) );
57 c->setStoreItems(m_storeItems);
58 c->setMaxItemCount(m_maxItemCount);
59
60 if ( !c->loadItems() ) {
61 createLoadButton();
62 return nullptr;
63 }
64
65 connect( c.get(), &ClipboardBrowser::itemSelectionChanged,
66 this, &ClipboardBrowserPlaceholder::restartExpiring);
67 connect( c.get(), &ClipboardBrowser::itemsChanged,
68 this, &ClipboardBrowserPlaceholder::restartExpiring);
69
70 m_browser = c.release();
71 setActiveWidget(m_browser);
72
73 restartExpiring();
74
75 emit browserCreated(m_browser);
76 return m_browser;
77 }
78
setTabName(const QString & tabName)79 bool ClipboardBrowserPlaceholder::setTabName(const QString &tabName)
80 {
81 if ( isEditorOpen() ) {
82 if ( !m_browser->setTabName(tabName) )
83 return false;
84 reloadBrowser();
85 } else {
86 unloadBrowser();
87 if ( !moveItems(m_tabName, tabName) ) {
88 if ( isVisible() )
89 createBrowser();
90 return false;
91 }
92 }
93
94 ::removeItems(m_tabName);
95 m_tabName = tabName;
96
97 if ( isVisible() )
98 createBrowser();
99
100 return true;
101 }
102
setMaxItemCount(int count)103 void ClipboardBrowserPlaceholder::setMaxItemCount(int count)
104 {
105 m_maxItemCount = count;
106 if (m_browser)
107 m_browser->setMaxItemCount(count);
108 }
109
setStoreItems(bool store)110 void ClipboardBrowserPlaceholder::setStoreItems(bool store)
111 {
112 m_storeItems = store;
113 if (m_browser)
114 m_browser->setStoreItems(store);
115 }
116
removeItems()117 void ClipboardBrowserPlaceholder::removeItems()
118 {
119 unloadBrowser();
120
121 ::removeItems(m_tabName);
122 }
123
isDataLoaded() const124 bool ClipboardBrowserPlaceholder::isDataLoaded() const
125 {
126 return m_browser != nullptr;
127 }
128
createBrowserAgain()129 ClipboardBrowser *ClipboardBrowserPlaceholder::createBrowserAgain()
130 {
131 delete m_loadButton;
132 m_loadButton = nullptr;
133 return createBrowser();
134 }
135
reloadBrowser()136 void ClipboardBrowserPlaceholder::reloadBrowser()
137 {
138 if ( isEditorOpen() ) {
139 connect( m_browser, &ClipboardBrowser::editingFinished,
140 this, &ClipboardBrowserPlaceholder::reloadBrowser, Qt::UniqueConnection );
141 } else {
142 unloadBrowser();
143 if ( isVisible() )
144 createBrowser();
145 }
146 }
147
showEvent(QShowEvent * event)148 void ClipboardBrowserPlaceholder::showEvent(QShowEvent *event)
149 {
150 QWidget::showEvent(event);
151 QTimer::singleShot(0, this, [this](){
152 if ( isVisible() )
153 createBrowser();
154 });
155 }
156
hideEvent(QHideEvent * event)157 void ClipboardBrowserPlaceholder::hideEvent(QHideEvent *event)
158 {
159 restartExpiring();
160 QWidget::hideEvent(event);
161 }
162
expire()163 bool ClipboardBrowserPlaceholder::expire()
164 {
165 if (!m_browser)
166 return true;
167
168 if (canExpire()) {
169 COPYQ_LOG( QString("Tab \"%1\": Expired").arg(m_tabName) );
170 unloadBrowser();
171 return true;
172 }
173
174 restartExpiring();
175 return false;
176 }
177
setActiveWidget(QWidget * widget)178 void ClipboardBrowserPlaceholder::setActiveWidget(QWidget *widget)
179 {
180 layout()->addWidget(widget);
181 setFocusProxy(widget);
182 widget->show();
183 if (isVisible())
184 widget->setFocus();
185 }
186
createLoadButton()187 void ClipboardBrowserPlaceholder::createLoadButton()
188 {
189 if (m_loadButton)
190 return;
191
192 m_loadButton = new QPushButton(this);
193 m_loadButton->setObjectName("ClipboardBrowserRefreshButton");
194 m_loadButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
195 m_loadButton->setFlat(true);
196
197 const QIcon icon( getIcon("", IconRedo) );
198 m_loadButton->setIconSize( QSize(64, 64) );
199 m_loadButton->setIcon(icon);
200
201 connect( m_loadButton, &QAbstractButton::clicked,
202 this, &ClipboardBrowserPlaceholder::createBrowserAgain );
203
204 setActiveWidget(m_loadButton);
205 }
206
unloadBrowser()207 void ClipboardBrowserPlaceholder::unloadBrowser()
208 {
209 if (!m_browser)
210 return;
211
212 COPYQ_LOG( QString("Tab \"%1\": Unloading").arg(m_tabName) );
213
214 // WORKAROUND: This is needed on macOS, to fix refocusing correct widget later.
215 m_browser->clearFocus();
216
217 m_browser->hide();
218 m_browser->saveUnsavedItems();
219 m_browser->deleteLater();
220 m_browser = nullptr;
221
222 emit browserDestroyed();
223 }
224
canExpire() const225 bool ClipboardBrowserPlaceholder::canExpire() const
226 {
227 return m_browser
228 && m_storeItems
229 && !m_browser->isVisible()
230 && !isEditorOpen();
231 }
232
restartExpiring()233 void ClipboardBrowserPlaceholder::restartExpiring()
234 {
235 const int expireTimeoutMs = 60000 * m_sharedData->minutesToExpire;
236 if (expireTimeoutMs > 0)
237 m_timerExpire.start(expireTimeoutMs);
238 }
239
isEditorOpen() const240 bool ClipboardBrowserPlaceholder::isEditorOpen() const
241 {
242 return m_browser && (
243 m_browser->isInternalEditorOpen()
244 || m_browser->isExternalEditorOpen() );
245 }
246