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