]> git.sur5r.net Git - minitube/blob - src/searchview.cpp
522701e29b3fed0b290c134f6819da28f3f12f3f
[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
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::smallBold();
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:normal'>" +
88                        tr("Welcome to <a href='%1'>%2</a>,")
89                        // .replace("<a ", "<a style='color:palette(text)'")
90                        .replace("<a href", "<a style='text-decoration:none; color:palette(text); font-weight:bold' href")
91                        .arg(Constants::WEBSITE, Constants::NAME)
92                        + "</h1>", this);
93     welcomeLabel->setOpenExternalLinks(true);
94 #ifdef APP_WIN
95     QFont f = welcomeLabel->font();
96     f.setHintingPreference(QFont::PreferNoHinting);
97     f.setFamily("Segoe UI Light");
98     welcomeLabel->setFont(f);
99 #endif
100     layout->addWidget(welcomeLabel);
101
102     layout->addSpacing(PADDING / 2);
103
104     QBoxLayout *tipLayout = new QHBoxLayout();
105     tipLayout->setSpacing(10);
106
107     //: "Enter", as in "type". The whole phrase says: "Enter a keyword to start watching videos"
108     QLabel *tipLabel = new QLabel(tr("Enter"), this);
109     tipLabel->setFont(biggerFont);
110     tipLayout->addWidget(tipLabel);
111
112     typeCombo = new QComboBox(this);
113     typeCombo->addItem(tr("a keyword"));
114     typeCombo->addItem(tr("a channel"));
115     typeCombo->setFont(biggerFont);
116     connect(typeCombo, SIGNAL(currentIndexChanged(int)), SLOT(searchTypeChanged(int)));
117     tipLayout->addWidget(typeCombo);
118
119     tipLabel = new QLabel(tr("to start watching videos."), this);
120     tipLabel->setFont(biggerFont);
121     tipLayout->addWidget(tipLabel);
122     layout->addLayout(tipLayout);
123
124     layout->addSpacing(PADDING / 2);
125
126     QHBoxLayout *searchLayout = new QHBoxLayout();
127     searchLayout->setAlignment(Qt::AlignVCenter);
128
129     queryEdit = new SearchLineEdit(this);
130     queryEdit->setFont(biggerFont);
131     queryEdit->setMinimumWidth(queryEdit->fontInfo().pixelSize()*15);
132     connect(queryEdit, SIGNAL(search(const QString&)), SLOT(watch(const QString&)));
133     connect(queryEdit, SIGNAL(textChanged(const QString &)), SLOT(textChanged(const QString &)));
134     connect(queryEdit, SIGNAL(suggestionAccepted(const QString&)), SLOT(watch(const QString&)));
135
136     youtubeSuggest = new YTSuggester(this);
137     channelSuggest = new ChannelSuggest(this);
138     searchTypeChanged(0);
139
140     searchLayout->addWidget(queryEdit);
141     searchLayout->addSpacing(10);
142
143     watchButton = new QPushButton(tr("Watch"), this);
144     watchButton->setDefault(true);
145     watchButton->setEnabled(false);
146     watchButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
147     connect(watchButton, SIGNAL(clicked()), this, SLOT(watch()));
148     searchLayout->addWidget(watchButton);
149
150     layout->addItem(searchLayout);
151
152     layout->addSpacing(PADDING / 2);
153
154     QHBoxLayout *otherLayout = new QHBoxLayout();
155     otherLayout->setMargin(0);
156     otherLayout->setSpacing(10);
157
158     recentKeywordsLayout = new QVBoxLayout();
159     recentKeywordsLayout->setSpacing(5);
160     recentKeywordsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
161     recentKeywordsLabel = new QLabel(tr("Recent keywords").toUpper(), this);
162     recentKeywordsLabel->setProperty("recentHeader", true);
163     recentKeywordsLabel->setForegroundRole(QPalette::Dark);
164     recentKeywordsLabel->hide();
165     recentKeywordsLabel->setFont(smallerFont);
166     recentKeywordsLayout->addWidget(recentKeywordsLabel);
167
168     otherLayout->addLayout(recentKeywordsLayout);
169
170     // recent channels
171     recentChannelsLayout = new QVBoxLayout();
172     recentChannelsLayout->setSpacing(5);
173     recentChannelsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
174     recentChannelsLabel = new QLabel(tr("Recent channels").toUpper(), this);
175     recentChannelsLabel->setProperty("recentHeader", true);
176     recentChannelsLabel->setForegroundRole(QPalette::Dark);
177     recentChannelsLabel->hide();
178     recentChannelsLabel->setFont(smallerFont);
179     recentChannelsLayout->addWidget(recentChannelsLabel);
180
181     otherLayout->addLayout(recentChannelsLayout);
182
183     layout->addLayout(otherLayout);
184
185     mainLayout->addStretch();
186
187 #ifdef APP_ACTIVATION
188     if (!Activation::instance().isActivated())
189         mainLayout->addWidget(Extra::buyButton(tr("Get the full version")), 0, Qt::AlignRight);
190 #endif
191 }
192
193 void SearchView::appear() {
194     updateRecentKeywords();
195     updateRecentChannels();
196     queryEdit->selectAll();
197     queryEdit->enableSuggest();
198     QTimer::singleShot(0, queryEdit, SLOT(setFocus()));
199 }
200
201 void SearchView::updateRecentKeywords() {
202
203     // cleanup
204     QLayoutItem *item;
205     while ((item = recentKeywordsLayout->takeAt(1)) != 0) {
206         item->widget()->close();
207         delete item;
208     }
209
210     // load
211     QSettings settings;
212     QStringList keywords = settings.value(recentKeywordsKey).toStringList();
213     recentKeywordsLabel->setVisible(!keywords.isEmpty());
214     The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
215
216     foreach (QString keyword, keywords) {
217         QString link = keyword;
218         QString display = keyword;
219         if (keyword.startsWith("http://") || keyword.startsWith("https://")) {
220             int separator = keyword.indexOf("|");
221             if (separator > 0 && separator + 1 < keyword.length()) {
222                 link = keyword.left(separator);
223                 display = keyword.mid(separator+1);
224             }
225         }
226         bool needStatusTip = false;
227         if (display.length() > 24) {
228             display.truncate(24);
229             display.append("...");
230             needStatusTip = true;
231         }
232         QLabel *itemLabel = new QLabel("<a href=\"" + link
233                                        + "\" style=\"color:palette(text); text-decoration:none\">"
234                                        + display + "</a>", this);
235         itemLabel->setAttribute(Qt::WA_DeleteOnClose);
236         itemLabel->setProperty("recentItem", true);
237         itemLabel->setMaximumWidth(queryEdit->width() + watchButton->width());
238         // itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
239         // Make links navigable with the keyboard too
240         itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
241         if (needStatusTip)
242             itemLabel->setStatusTip(link);
243         connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchKeywords(QString)));
244         recentKeywordsLayout->addWidget(itemLabel);
245     }
246
247 }
248
249 void SearchView::updateRecentChannels() {
250
251     // cleanup
252     QLayoutItem *item;
253     while ((item = recentChannelsLayout->takeAt(1)) != 0) {
254         item->widget()->close();
255         delete item;
256     }
257
258     // load
259     QSettings settings;
260     QStringList keywords = settings.value(recentChannelsKey).toStringList();
261     recentChannelsLabel->setVisible(!keywords.isEmpty());
262     // TODO The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
263
264     foreach (QString keyword, keywords) {
265         QString link = keyword;
266         QString display = keyword;
267         int separator = keyword.indexOf('|');
268         if (separator > 0 && separator + 1 < keyword.length()) {
269             link = keyword.left(separator);
270             display = keyword.mid(separator+1);
271         }
272         QLabel *itemLabel = new QLabel("<a href=\"" + link
273                                        + "\" style=\"color:palette(text); text-decoration:none\">"
274                                        + display + "</a>", this);
275         itemLabel->setAttribute(Qt::WA_DeleteOnClose);
276         itemLabel->setProperty("recentItem", true);
277         itemLabel->setMaximumWidth(queryEdit->width() + watchButton->width());
278         // itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
279         // Make links navigable with the keyboard too
280         itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
281
282         connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchChannel(QString)));
283         recentChannelsLayout->addWidget(itemLabel);
284     }
285
286 }
287
288 void SearchView::watch() {
289     QString query = queryEdit->text();
290     watch(query);
291 }
292
293 void SearchView::textChanged(const QString &text) {
294     watchButton->setEnabled(!text.simplified().isEmpty());
295 }
296
297 void SearchView::watch(QString query) {
298
299     query = query.simplified();
300
301     // check for empty query
302     if (query.length() == 0) {
303         queryEdit->setFocus(Qt::OtherFocusReason);
304         return;
305     }
306
307     SearchParams *searchParams = new SearchParams();
308     if (typeCombo->currentIndex() == 0)
309         searchParams->setKeywords(query);
310     else {
311         // remove spaces from channel name
312         query = query.simplified();
313         searchParams->setAuthor(query);
314         searchParams->setSortBy(SearchParams::SortByNewest);
315     }
316
317     // go!
318     emit search(searchParams);
319 }
320
321 void SearchView::watchChannel(QString channel) {
322
323     channel = channel.simplified();
324
325     // check for empty query
326     if (channel.length() == 0) {
327         queryEdit->setFocus(Qt::OtherFocusReason);
328         return;
329     }
330
331     // remove spaces from channel name
332     channel = channel.remove(" ");
333
334     SearchParams *searchParams = new SearchParams();
335     searchParams->setAuthor(channel);
336     searchParams->setSortBy(SearchParams::SortByNewest);
337
338     // go!
339     emit search(searchParams);
340 }
341
342 void SearchView::watchKeywords(QString query) {
343
344     query = query.simplified();
345
346     // check for empty query
347     if (query.length() == 0) {
348         queryEdit->setFocus(Qt::OtherFocusReason);
349         return;
350     }
351
352     if (typeCombo->currentIndex() == 0) {
353         queryEdit->setText(query);
354         watchButton->setEnabled(true);
355     }
356
357     SearchParams *searchParams = new SearchParams();
358     searchParams->setKeywords(query);
359
360     // go!
361     emit search(searchParams);
362 }
363
364 void SearchView::paintEvent(QPaintEvent *event) {
365     QWidget::paintEvent(event);
366 #if defined(APP_MAC) | defined(APP_WIN)
367     QBrush brush;
368     if (window()->isActiveWindow()) {
369         brush = QBrush(QColor(0xdd, 0xe4, 0xeb));
370     } else {
371         brush = palette().window();
372     }
373     QPainter painter(this);
374     painter.fillRect(0, 0, width(), height(), brush);
375     painter.end();
376 #endif
377 #ifdef APP_UBUNTU
378     QStyleOption o;
379     o.initFrom(this);
380     QPainter p(this);
381     style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
382 #endif
383     // PainterUtils::topShadow(this);
384 }
385
386 void SearchView::searchTypeChanged(int index) {
387     if (index == 0) {
388         queryEdit->setSuggester(youtubeSuggest);
389     } else {
390         queryEdit->setSuggester(channelSuggest);
391     }
392     queryEdit->selectAll();
393     queryEdit->setFocus();
394 }