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