1 #include "searchview.h"
4 #include "searchparams.h"
5 #include "ytsuggester.h"
6 #include "channelsuggest.h"
8 #include "searchlineedit_mac.h"
10 #include "searchlineedit.h"
16 #include "activation.h"
18 #include "mainwindow.h"
21 QHash<QString, QAction*>* globalActions();
24 static const QString recentKeywordsKey = "recentKeywords";
25 static const QString recentChannelsKey = "recentChannels";
26 static const int PADDING = 30;
28 SearchView::SearchView(QWidget *parent) : QWidget(parent) {
30 QFont biggerFont = FontUtils::big();
31 QFont smallerFont = FontUtils::smallBold();
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);
39 QBoxLayout *mainLayout = new QVBoxLayout(this);
40 mainLayout->setMargin(PADDING);
41 mainLayout->setSpacing(0);
43 // hidden message widget
44 message = new QLabel(this);
46 mainLayout->addWidget(message);
48 mainLayout->addStretch();
50 QBoxLayout *hLayout = new QHBoxLayout();
51 hLayout->setAlignment(Qt::AlignCenter);
52 mainLayout->addLayout(hLayout);
54 QLabel *logo = new QLabel(this);
55 logo->setPixmap(QPixmap(":/images/app.png"));
56 hLayout->addWidget(logo, 0, Qt::AlignTop);
57 hLayout->addSpacing(PADDING);
59 QVBoxLayout *layout = new QVBoxLayout();
60 layout->setAlignment(Qt::AlignCenter);
61 hLayout->addLayout(layout);
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)
70 welcomeLabel->setOpenExternalLinks(true);
71 layout->addWidget(welcomeLabel);
73 layout->addSpacing(PADDING / 2);
75 QBoxLayout *tipLayout = new QHBoxLayout();
76 tipLayout->setSpacing(10);
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);
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);
90 tipLabel = new QLabel(tr("to start watching videos."), this);
91 tipLabel->setFont(biggerFont);
92 tipLayout->addWidget(tipLabel);
93 layout->addLayout(tipLayout);
95 layout->addSpacing(PADDING / 2);
97 QHBoxLayout *searchLayout = new QHBoxLayout();
98 searchLayout->setAlignment(Qt::AlignVCenter);
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&)));
107 youtubeSuggest = new YTSuggester(this);
108 channelSuggest = new ChannelSuggest(this);
109 searchTypeChanged(0);
111 searchLayout->addWidget(queryEdit);
112 searchLayout->addSpacing(10);
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);
121 layout->addItem(searchLayout);
123 layout->addSpacing(PADDING / 2);
125 QHBoxLayout *otherLayout = new QHBoxLayout();
126 otherLayout->setMargin(0);
127 otherLayout->setSpacing(10);
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);
139 otherLayout->addLayout(recentKeywordsLayout);
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);
152 otherLayout->addLayout(recentChannelsLayout);
154 layout->addLayout(otherLayout);
156 mainLayout->addStretch();
158 #ifdef APP_ACTIVATION
159 if (!Activation::instance().isActivated())
160 mainLayout->addWidget(Extra::buyButton(tr("Get the full version")), 0, Qt::AlignRight);
164 void SearchView::appear() {
165 updateRecentKeywords();
166 updateRecentChannels();
167 queryEdit->selectAll();
168 queryEdit->enableSuggest();
169 QTimer::singleShot(0, queryEdit, SLOT(setFocus()));
172 void SearchView::updateRecentKeywords() {
176 while ((item = recentKeywordsLayout->takeAt(1)) != 0) {
177 item->widget()->close();
183 QStringList keywords = settings.value(recentKeywordsKey).toStringList();
184 recentKeywordsLabel->setVisible(!keywords.isEmpty());
185 The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
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);
197 bool needStatusTip = false;
198 if (display.length() > 24) {
199 display.truncate(24);
200 display.append("...");
201 needStatusTip = true;
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);
213 itemLabel->setStatusTip(link);
214 connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchKeywords(QString)));
215 recentKeywordsLayout->addWidget(itemLabel);
220 void SearchView::updateRecentChannels() {
224 while ((item = recentChannelsLayout->takeAt(1)) != 0) {
225 item->widget()->close();
231 QStringList keywords = settings.value(recentChannelsKey).toStringList();
232 recentChannelsLabel->setVisible(!keywords.isEmpty());
233 // TODO The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
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);
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);
253 connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchChannel(QString)));
254 recentChannelsLayout->addWidget(itemLabel);
259 void SearchView::watch() {
260 QString query = queryEdit->text();
264 void SearchView::textChanged(const QString &text) {
265 watchButton->setEnabled(!text.simplified().isEmpty());
268 void SearchView::watch(QString query) {
270 query = query.simplified();
272 // check for empty query
273 if (query.length() == 0) {
274 queryEdit->setFocus(Qt::OtherFocusReason);
278 SearchParams *searchParams = new SearchParams();
279 if (typeCombo->currentIndex() == 0)
280 searchParams->setKeywords(query);
282 // remove spaces from channel name
283 query = query.replace(" ", "");
284 searchParams->setAuthor(query);
285 searchParams->setSortBy(SearchParams::SortByNewest);
289 emit search(searchParams);
292 void SearchView::watchChannel(QString channel) {
294 channel = channel.simplified();
296 // check for empty query
297 if (channel.length() == 0) {
298 queryEdit->setFocus(Qt::OtherFocusReason);
302 // remove spaces from channel name
303 channel = channel.remove(" ");
305 SearchParams *searchParams = new SearchParams();
306 searchParams->setAuthor(channel);
307 searchParams->setSortBy(SearchParams::SortByNewest);
310 emit search(searchParams);
313 void SearchView::watchKeywords(QString query) {
315 query = query.simplified();
317 // check for empty query
318 if (query.length() == 0) {
319 queryEdit->setFocus(Qt::OtherFocusReason);
323 if (typeCombo->currentIndex() == 0) {
324 queryEdit->setText(query);
325 watchButton->setEnabled(true);
328 SearchParams *searchParams = new SearchParams();
329 searchParams->setKeywords(query);
332 emit search(searchParams);
335 void SearchView::paintEvent(QPaintEvent * /*event*/) {
336 QPainter painter(this);
338 #if defined(APP_MAC) | defined(APP_WIN)
340 if (window()->isActiveWindow()) {
341 brush = QBrush(QColor(0xdd, 0xe4, 0xeb));
343 brush = palette().window();
345 painter.fillRect(0, 0, width(), height(), brush);
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));
359 painter.fillRect(r.x(), r.y(), r.width(), shadowHeight, QBrush(shadow));
362 void SearchView::searchTypeChanged(int index) {
364 queryEdit->setSuggester(youtubeSuggest);
366 queryEdit->setSuggester(channelSuggest);
368 queryEdit->selectAll();
369 queryEdit->setFocus();