]> git.sur5r.net Git - minitube/blob - src/searchview.cpp
Font tweaks, definition action
[minitube] / src / searchview.cpp
1 /* $BEGIN_LICENSE
2
3 This file is part of Minitube.
4 Copyright 2009, Flavio Tordini <flavio.tordini@gmail.com>
5
6 Minitube 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 Minitube 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 Minitube.  If not, see <http://www.gnu.org/licenses/>.
18
19 $END_LICENSE */
20
21 #include "searchview.h"
22 #include "constants.h"
23 #include "fontutils.h"
24 #include "searchparams.h"
25 #include "ytsuggester.h"
26 #include "channelsuggest.h"
27 #ifdef APP_MAC_SEARCHFIELD
28 #include "searchlineedit_mac.h"
29 #else
30 #include "searchlineedit.h"
31 #endif
32 #ifdef APP_EXTRA
33 #include "extra.h"
34 #endif
35 #ifdef APP_ACTIVATION
36 #include "activation.h"
37 #endif
38 #include "mainwindow.h"
39 #include "painterutils.h"
40
41 namespace The {
42 QHash<QString, QAction*>* globalActions();
43 }
44
45 static const QString recentKeywordsKey = "recentKeywords";
46 static const QString recentChannelsKey = "recentChannels";
47 static const int PADDING = 30;
48
49 SearchView::SearchView(QWidget *parent) : QWidget(parent) {
50
51     QFont biggerFont = FontUtils::big();
52     QFont smallerFont = FontUtils::small();
53
54 #if defined(APP_MAC) | defined(APP_WIN)
55     // speedup painting since we'll paint the whole background
56     // by ourselves anyway in paintEvent()
57     setAttribute(Qt::WA_OpaquePaintEvent);
58 #endif
59
60     setAutoFillBackground(true);
61
62     QBoxLayout *mainLayout = new QVBoxLayout(this);
63     mainLayout->setMargin(PADDING);
64     mainLayout->setSpacing(0);
65
66     // hidden message widget
67     message = new QLabel(this);
68     message->hide();
69     mainLayout->addWidget(message);
70
71     mainLayout->addStretch();
72
73     QBoxLayout *hLayout = new QHBoxLayout();
74     hLayout->setAlignment(Qt::AlignCenter);
75     mainLayout->addLayout(hLayout);
76
77     QLabel *logo = new QLabel(this);
78     logo->setPixmap(QPixmap(":/images/app.png"));
79     hLayout->addWidget(logo, 0, Qt::AlignTop);
80     hLayout->addSpacing(PADDING);
81
82     QVBoxLayout *layout = new QVBoxLayout();
83     layout->setAlignment(Qt::AlignCenter);
84     hLayout->addLayout(layout);
85
86     QLabel *welcomeLabel =
87             new QLabel("<h1 style='font-weight:100'>" +
88                        tr("Welcome to <a href='%1'>%2</a>,")
89                        // .replace("<a ", "<a style='color:palette(text)'")
90                        .replace("<a ", "<a style='text-decoration:none; color:palette(text);font-weight:normal' ")
91                        .arg(Constants::WEBSITE, Constants::NAME)
92                        + "</h1>", this);
93     welcomeLabel->setOpenExternalLinks(true);
94     welcomeLabel->setProperty("heading", true);
95 #ifdef APP_MAC
96     QFont f = welcomeLabel->font();
97     f.setFamily("Helvetica Neue");
98     f.setStyleName("Thin");
99     welcomeLabel->setFont(f);
100 #elif APP_WIN
101     QFont f = welcomeLabel->font();
102     f.setFamily("Segoe UI Light");
103     welcomeLabel->setFont(f);
104 #endif
105     layout->addWidget(welcomeLabel);
106
107     layout->addSpacing(PADDING / 2);
108
109     QBoxLayout *tipLayout = new QHBoxLayout();
110     tipLayout->setSpacing(10);
111
112     //: "Enter", as in "type". The whole phrase says: "Enter a keyword to start watching videos"
113     QLabel *tipLabel = new QLabel(tr("Enter"), this);
114 #ifndef APP_MAC
115     tipLabel->setFont(biggerFont);
116 #endif
117     tipLayout->addWidget(tipLabel);
118
119     typeCombo = new QComboBox(this);
120     typeCombo->addItem(tr("a keyword"));
121     typeCombo->addItem(tr("a channel"));
122 #ifndef APP_MAC
123     typeCombo->setFont(biggerFont);
124 #endif
125     connect(typeCombo, SIGNAL(currentIndexChanged(int)), SLOT(searchTypeChanged(int)));
126     tipLayout->addWidget(typeCombo);
127
128     tipLabel = new QLabel(tr("to start watching videos."), this);
129 #ifndef APP_MAC
130     tipLabel->setFont(biggerFont);
131 #endif
132     tipLayout->addWidget(tipLabel);
133     layout->addLayout(tipLayout);
134
135     layout->addSpacing(PADDING / 2);
136
137     QHBoxLayout *searchLayout = new QHBoxLayout();
138     searchLayout->setAlignment(Qt::AlignVCenter);
139
140     queryEdit = new SearchLineEdit(this);
141 #ifndef APP_MAC_SEARCHFIELD
142     queryEdit->setFont(biggerFont);
143 #endif
144     connect(queryEdit, SIGNAL(search(const QString&)), SLOT(watch(const QString&)));
145     connect(queryEdit, SIGNAL(textEdited(const QString &)), SLOT(textChanged(const QString &)));
146     connect(queryEdit, SIGNAL(suggestionAccepted(Suggestion*)), SLOT(suggestionAccepted(Suggestion*)));
147
148     youtubeSuggest = new YTSuggester(this);
149     channelSuggest = new ChannelSuggest(this);
150     searchTypeChanged(0);
151
152     searchLayout->addWidget(queryEdit);
153     searchLayout->addSpacing(10);
154
155     watchButton = new QPushButton(tr("Watch"), this);
156     watchButton->setDefault(true);
157     watchButton->setEnabled(false);
158     watchButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
159     connect(watchButton, SIGNAL(clicked()), this, SLOT(watch()));
160     searchLayout->addWidget(watchButton);
161
162     layout->addItem(searchLayout);
163
164     layout->addSpacing(PADDING / 2);
165
166     QHBoxLayout *otherLayout = new QHBoxLayout();
167     otherLayout->setMargin(0);
168     otherLayout->setSpacing(10);
169
170     recentKeywordsLayout = new QVBoxLayout();
171     recentKeywordsLayout->setSpacing(5);
172     recentKeywordsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
173     recentKeywordsLabel = new QLabel(tr("Recent keywords").toUpper(), this);
174     recentKeywordsLabel->setProperty("recentHeader", true);
175     recentKeywordsLabel->setForegroundRole(QPalette::Dark);
176     recentKeywordsLabel->hide();
177     recentKeywordsLabel->setFont(smallerFont);
178     recentKeywordsLayout->addWidget(recentKeywordsLabel);
179
180     otherLayout->addLayout(recentKeywordsLayout);
181
182     // recent channels
183     recentChannelsLayout = new QVBoxLayout();
184     recentChannelsLayout->setSpacing(5);
185     recentChannelsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
186     recentChannelsLabel = new QLabel(tr("Recent channels").toUpper(), this);
187     recentChannelsLabel->setProperty("recentHeader", true);
188     recentChannelsLabel->setForegroundRole(QPalette::Dark);
189     recentChannelsLabel->hide();
190     recentChannelsLabel->setFont(smallerFont);
191     recentChannelsLayout->addWidget(recentChannelsLabel);
192
193     otherLayout->addLayout(recentChannelsLayout);
194
195     layout->addLayout(otherLayout);
196
197     mainLayout->addStretch();
198
199 #ifdef APP_ACTIVATION
200     if (!Activation::instance().isActivated())
201         mainLayout->addWidget(Extra::buyButton(tr("Get the full version")), 0, Qt::AlignRight);
202 #endif
203 }
204
205 void SearchView::appear() {
206     setUpdatesEnabled(false);
207     updateRecentKeywords();
208     updateRecentChannels();
209     queryEdit->selectAll();
210     queryEdit->enableSuggest();
211     setUpdatesEnabled(true);
212
213     MainWindow::instance()->showActionInStatusBar(The::globalActions()->value("definition"), true);
214
215     queryEdit->setFocus();
216     QTimer::singleShot(100, queryEdit, SLOT(setFocus()));
217 }
218
219 void SearchView::disappear() {
220     MainWindow::instance()->showActionInStatusBar(The::globalActions()->value("definition"), false);
221 }
222
223 void SearchView::updateRecentKeywords() {
224
225     // cleanup
226     QLayoutItem *item;
227     while ((item = recentKeywordsLayout->takeAt(1)) != 0) {
228         item->widget()->close();
229         delete item;
230     }
231
232     // load
233     QSettings settings;
234     QStringList keywords = settings.value(recentKeywordsKey).toStringList();
235     recentKeywordsLabel->setVisible(!keywords.isEmpty());
236     The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
237
238     foreach (const QString &keyword, keywords) {
239         QString link = keyword;
240         QString display = keyword;
241         if (keyword.startsWith("http://") || keyword.startsWith("https://")) {
242             int separator = keyword.indexOf("|");
243             if (separator > 0 && separator + 1 < keyword.length()) {
244                 link = keyword.left(separator);
245                 display = keyword.mid(separator+1);
246             }
247         }
248         bool needStatusTip = false;
249         if (display.length() > 24) {
250             display.truncate(24);
251             display.append("...");
252             needStatusTip = true;
253         }
254         QLabel *itemLabel = new QLabel("<a href=\"" + link
255                                        + "\" style=\"color:palette(text); text-decoration:none\">"
256                                        + display + "</a>", this);
257         itemLabel->setAttribute(Qt::WA_DeleteOnClose);
258         itemLabel->setProperty("recentItem", true);
259         itemLabel->setMaximumWidth(queryEdit->width() + watchButton->width());
260         // itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
261         // Make links navigable with the keyboard too
262         itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
263         if (needStatusTip)
264             itemLabel->setStatusTip(link);
265         connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchKeywords(QString)));
266         recentKeywordsLayout->addWidget(itemLabel);
267     }
268
269 }
270
271 void SearchView::updateRecentChannels() {
272
273     // cleanup
274     QLayoutItem *item;
275     while ((item = recentChannelsLayout->takeAt(1)) != 0) {
276         item->widget()->close();
277         delete item;
278     }
279
280     // load
281     QSettings settings;
282     QStringList keywords = settings.value(recentChannelsKey).toStringList();
283     recentChannelsLabel->setVisible(!keywords.isEmpty());
284     // TODO The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
285
286     foreach (const QString &keyword, keywords) {
287         QString link = keyword;
288         QString display = keyword;
289         int separator = keyword.indexOf('|');
290         if (separator > 0 && separator + 1 < keyword.length()) {
291             link = keyword.left(separator);
292             display = keyword.mid(separator+1);
293         }
294         QLabel *itemLabel = new QLabel("<a href=\"" + link
295                                        + "\" style=\"color:palette(text); text-decoration:none\">"
296                                        + display + "</a>", this);
297         itemLabel->setAttribute(Qt::WA_DeleteOnClose);
298         itemLabel->setProperty("recentItem", true);
299         itemLabel->setMaximumWidth(queryEdit->width() + watchButton->width());
300         // itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
301         // Make links navigable with the keyboard too
302         itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
303
304         connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchChannel(QString)));
305         recentChannelsLayout->addWidget(itemLabel);
306     }
307
308 }
309
310 void SearchView::watch() {
311     QString query = queryEdit->text();
312     watch(query);
313 }
314
315 void SearchView::textChanged(const QString &text) {
316     watchButton->setEnabled(!text.simplified().isEmpty());
317 }
318
319 void SearchView::watch(const QString &query) {
320     QString q = query.simplified();
321
322     // check for empty query
323     if (q.length() == 0) {
324         queryEdit->setFocus(Qt::OtherFocusReason);
325         return;
326     }
327
328     SearchParams *searchParams = new SearchParams();
329     if (typeCombo->currentIndex() == 0)
330         searchParams->setKeywords(q);
331     else {
332         // remove spaces from channel name
333         q.remove(' ');
334         searchParams->setChannelId(q);
335         searchParams->setSortBy(SearchParams::SortByNewest);
336     }
337
338     // go!
339     emit search(searchParams);
340 }
341
342 void SearchView::watchChannel(const QString &channelId) {
343     if (channelId.length() == 0) {
344         queryEdit->setFocus(Qt::OtherFocusReason);
345         return;
346     }
347
348     QString id = channelId;
349
350     // Fix old settings
351     if (!id.startsWith("UC")) id = "UC" + id;
352
353     SearchParams *searchParams = new SearchParams();
354     searchParams->setChannelId(id);
355     searchParams->setSortBy(SearchParams::SortByNewest);
356
357     // go!
358     emit search(searchParams);
359 }
360
361 void SearchView::watchKeywords(const QString &query) {
362     QString q = query.simplified();
363
364     // check for empty query
365     if (query.length() == 0) {
366         queryEdit->setFocus(Qt::OtherFocusReason);
367         return;
368     }
369
370     if (typeCombo->currentIndex() == 0) {
371         queryEdit->setText(q);
372         watchButton->setEnabled(true);
373     }
374
375     SearchParams *searchParams = new SearchParams();
376     searchParams->setKeywords(q);
377
378     // go!
379     emit search(searchParams);
380 }
381
382 void SearchView::paintEvent(QPaintEvent *event) {
383     QWidget::paintEvent(event);
384 #if defined(APP_MAC) | defined(APP_WIN)
385     QBrush brush;
386     if (window()->isActiveWindow()) {
387         // brush = QBrush(QColor(0xdd, 0xe4, 0xeb));
388         brush = Qt::white;
389     } else {
390         brush = palette().window();
391     }
392     QPainter painter(this);
393     painter.fillRect(0, 0, width(), height(), brush);
394     painter.end();
395 #endif
396 #ifdef APP_UBUNTU
397     QStyleOption o;
398     o.initFrom(this);
399     QPainter p(this);
400     style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
401 #endif
402     // PainterUtils::topShadow(this);
403 }
404
405 void SearchView::searchTypeChanged(int index) {
406     if (index == 0) {
407         queryEdit->setSuggester(youtubeSuggest);
408     } else {
409         queryEdit->setSuggester(channelSuggest);
410     }
411     queryEdit->selectAll();
412     queryEdit->setFocus();
413 }
414
415 void SearchView::suggestionAccepted(Suggestion *suggestion) {
416     if (suggestion->type == QLatin1String("channel")) {
417         watchChannel(suggestion->userData);
418     } else watch(suggestion->value);
419 }