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