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();
40 mainLayout->setMargin(PADDING);
41 mainLayout->setSpacing(0);
43 // hidden message widget
44 message = new QLabel(this);
46 mainLayout->addWidget(message);
48 mainLayout->addStretch();
49 mainLayout->addSpacing(PADDING);
51 QBoxLayout *hLayout = new QHBoxLayout();
52 hLayout->setAlignment(Qt::AlignCenter);
53 mainLayout->addLayout(hLayout);
55 QLabel *logo = new QLabel(this);
56 logo->setPixmap(QPixmap(":/images/app.png"));
57 hLayout->addWidget(logo, 0, Qt::AlignTop);
58 hLayout->addSpacing(PADDING);
60 QVBoxLayout *layout = new QVBoxLayout();
61 layout->setAlignment(Qt::AlignCenter);
62 hLayout->addLayout(layout);
64 QLabel *welcomeLabel =
65 new QLabel("<h1 style='font-weight:normal'>" +
66 tr("Welcome to <a href='%1'>%2</a>,")
67 // .replace("<a ", "<a style='color:palette(text)'")
68 .replace("<a href", "<a style='text-decoration:none; color:palette(text); font-weight:bold' href")
69 .arg(Constants::WEBSITE, Constants::NAME)
71 welcomeLabel->setOpenExternalLinks(true);
72 layout->addWidget(welcomeLabel);
74 layout->addSpacing(PADDING / 2);
76 QBoxLayout *tipLayout = new QHBoxLayout();
77 tipLayout->setSpacing(10);
79 //: "Enter", as in "type". The whole phrase says: "Enter a keyword to start watching videos"
80 QLabel *tipLabel = new QLabel(tr("Enter"), this);
81 tipLabel->setFont(biggerFont);
82 tipLayout->addWidget(tipLabel);
84 typeCombo = new QComboBox(this);
85 typeCombo->addItem(tr("a keyword"));
86 typeCombo->addItem(tr("a channel"));
87 typeCombo->setFont(biggerFont);
88 connect(typeCombo, SIGNAL(currentIndexChanged(int)), SLOT(searchTypeChanged(int)));
89 tipLayout->addWidget(typeCombo);
91 tipLabel = new QLabel(tr("to start watching videos."), this);
92 tipLabel->setFont(biggerFont);
93 tipLayout->addWidget(tipLabel);
94 layout->addLayout(tipLayout);
96 layout->addSpacing(PADDING / 2);
98 QHBoxLayout *searchLayout = new QHBoxLayout();
99 searchLayout->setAlignment(Qt::AlignVCenter);
101 queryEdit = new SearchLineEdit(this);
102 queryEdit->setFont(biggerFont);
103 queryEdit->setMinimumWidth(queryEdit->fontInfo().pixelSize()*15);
104 connect(queryEdit, SIGNAL(search(const QString&)), SLOT(watch(const QString&)));
105 connect(queryEdit, SIGNAL(textChanged(const QString &)), SLOT(textChanged(const QString &)));
106 connect(queryEdit, SIGNAL(suggestionAccepted(const QString&)), SLOT(watch(const QString&)));
108 youtubeSuggest = new YTSuggester(this);
109 channelSuggest = new ChannelSuggest(this);
110 searchTypeChanged(0);
112 searchLayout->addWidget(queryEdit);
113 searchLayout->addSpacing(10);
115 watchButton = new QPushButton(tr("Watch"), this);
116 watchButton->setDefault(true);
117 watchButton->setEnabled(false);
118 watchButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
119 connect(watchButton, SIGNAL(clicked()), this, SLOT(watch()));
120 searchLayout->addWidget(watchButton);
122 layout->addItem(searchLayout);
124 layout->addSpacing(PADDING / 2);
126 QHBoxLayout *otherLayout = new QHBoxLayout();
127 otherLayout->setMargin(0);
128 otherLayout->setSpacing(10);
130 recentKeywordsLayout = new QVBoxLayout();
131 recentKeywordsLayout->setSpacing(5);
132 recentKeywordsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
133 recentKeywordsLabel = new QLabel(tr("Recent keywords").toUpper(), this);
134 recentKeywordsLabel->setProperty("recentHeader", true);
135 recentKeywordsLabel->setForegroundRole(QPalette::Dark);
136 recentKeywordsLabel->hide();
137 recentKeywordsLabel->setFont(smallerFont);
138 recentKeywordsLayout->addWidget(recentKeywordsLabel);
140 otherLayout->addLayout(recentKeywordsLayout);
143 recentChannelsLayout = new QVBoxLayout();
144 recentChannelsLayout->setSpacing(5);
145 recentChannelsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
146 recentChannelsLabel = new QLabel(tr("Recent channels").toUpper(), this);
147 recentChannelsLabel->setProperty("recentHeader", true);
148 recentChannelsLabel->setForegroundRole(QPalette::Dark);
149 recentChannelsLabel->hide();
150 recentChannelsLabel->setFont(smallerFont);
151 recentChannelsLayout->addWidget(recentChannelsLabel);
153 otherLayout->addLayout(recentChannelsLayout);
155 layout->addLayout(otherLayout);
157 mainLayout->addSpacing(PADDING);
158 mainLayout->addStretch();
160 #ifdef APP_ACTIVATION
161 if (!Activation::instance().isActivated())
162 mainLayout->addWidget(Extra::buyButton(tr("Get the full version")), 0, Qt::AlignRight);
165 setLayout(mainLayout);
169 void SearchView::appear() {
170 updateRecentKeywords();
171 updateRecentChannels();
172 queryEdit->selectAll();
173 queryEdit->enableSuggest();
174 QTimer::singleShot(0, queryEdit, SLOT(setFocus()));
177 void SearchView::updateRecentKeywords() {
181 while ((item = recentKeywordsLayout->takeAt(1)) != 0) {
182 item->widget()->close();
188 QStringList keywords = settings.value(recentKeywordsKey).toStringList();
189 recentKeywordsLabel->setVisible(!keywords.isEmpty());
190 The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
192 foreach (QString keyword, keywords) {
193 QString link = keyword;
194 QString display = keyword;
195 if (keyword.startsWith("http://") || keyword.startsWith("https://")) {
196 int separator = keyword.indexOf("|");
197 if (separator > 0 && separator + 1 < keyword.length()) {
198 link = keyword.left(separator);
199 display = keyword.mid(separator+1);
202 bool needStatusTip = false;
203 if (display.length() > 24) {
204 display.truncate(24);
205 display.append("...");
206 needStatusTip = true;
208 QLabel *itemLabel = new QLabel("<a href=\"" + link
209 + "\" style=\"color:palette(text); text-decoration:none\">"
210 + display + "</a>", this);
211 itemLabel->setAttribute(Qt::WA_DeleteOnClose);
212 itemLabel->setProperty("recentItem", true);
213 itemLabel->setMaximumWidth(queryEdit->width() + watchButton->width());
214 // itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
215 // Make links navigable with the keyboard too
216 itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
218 itemLabel->setStatusTip(link);
219 connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchKeywords(QString)));
220 recentKeywordsLayout->addWidget(itemLabel);
225 void SearchView::updateRecentChannels() {
229 while ((item = recentChannelsLayout->takeAt(1)) != 0) {
230 item->widget()->close();
236 QStringList keywords = settings.value(recentChannelsKey).toStringList();
237 recentChannelsLabel->setVisible(!keywords.isEmpty());
238 // TODO The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
240 foreach (QString keyword, keywords) {
241 QString link = keyword;
242 QString display = keyword;
243 int separator = keyword.indexOf('|');
244 if (separator > 0 && separator + 1 < keyword.length()) {
245 link = keyword.left(separator);
246 display = keyword.mid(separator+1);
248 QLabel *itemLabel = new QLabel("<a href=\"" + link
249 + "\" style=\"color:palette(text); text-decoration:none\">"
250 + display + "</a>", this);
251 itemLabel->setAttribute(Qt::WA_DeleteOnClose);
252 itemLabel->setProperty("recentItem", true);
253 itemLabel->setMaximumWidth(queryEdit->width() + watchButton->width());
254 // itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
255 // Make links navigable with the keyboard too
256 itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
258 connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchChannel(QString)));
259 recentChannelsLayout->addWidget(itemLabel);
264 void SearchView::watch() {
265 QString query = queryEdit->text();
269 void SearchView::textChanged(const QString &text) {
270 watchButton->setEnabled(!text.simplified().isEmpty());
273 void SearchView::watch(QString query) {
275 query = query.simplified();
277 // check for empty query
278 if (query.length() == 0) {
279 queryEdit->setFocus(Qt::OtherFocusReason);
283 SearchParams *searchParams = new SearchParams();
284 if (typeCombo->currentIndex() == 0)
285 searchParams->setKeywords(query);
287 // remove spaces from channel name
288 query = query.replace(" ", "");
289 searchParams->setAuthor(query);
290 searchParams->setSortBy(SearchParams::SortByNewest);
294 emit search(searchParams);
297 void SearchView::watchChannel(QString channel) {
299 channel = channel.simplified();
301 // check for empty query
302 if (channel.length() == 0) {
303 queryEdit->setFocus(Qt::OtherFocusReason);
307 // remove spaces from channel name
308 channel = channel.remove(" ");
310 SearchParams *searchParams = new SearchParams();
311 searchParams->setAuthor(channel);
312 searchParams->setSortBy(SearchParams::SortByNewest);
315 emit search(searchParams);
318 void SearchView::watchKeywords(QString query) {
320 query = query.simplified();
322 // check for empty query
323 if (query.length() == 0) {
324 queryEdit->setFocus(Qt::OtherFocusReason);
328 if (typeCombo->currentIndex() == 0) {
329 queryEdit->setText(query);
330 watchButton->setEnabled(true);
333 SearchParams *searchParams = new SearchParams();
334 searchParams->setKeywords(query);
337 emit search(searchParams);
340 void SearchView::paintEvent(QPaintEvent * /*event*/) {
341 QPainter painter(this);
343 #if defined(APP_MAC) | defined(APP_WIN)
345 if (window()->isActiveWindow()) {
346 brush = QBrush(QColor(0xdd, 0xe4, 0xeb));
348 brush = palette().window();
350 painter.fillRect(0, 0, width(), height(), brush);
353 static QLinearGradient shadow;
354 static const int shadowHeight = 10;
355 if (shadow.stops().count() == 2) {
356 shadow.setFinalStop(0, shadowHeight);
357 const qreal initialOpacity = 96;
358 for (qreal i = 0; i <= 1; i += 1.0/shadowHeight) {
359 qreal opacity = qPow(initialOpacity, (1.0 - i)) - 1;
360 shadow.setColorAt(i, QColor(0x00, 0x00, 0x00, opacity));
364 painter.fillRect(r.x(), r.y(), r.width(), shadowHeight, QBrush(shadow));
367 void SearchView::searchTypeChanged(int index) {
369 queryEdit->setSuggester(youtubeSuggest);
371 queryEdit->setSuggester(channelSuggest);
373 queryEdit->selectAll();
374 queryEdit->setFocus();