This commit is contained in:
Arnaud Bienner 2014-04-09 23:08:14 +02:00
commit 532720ea79
75 changed files with 31524 additions and 32606 deletions

View File

@ -107,7 +107,6 @@ if(LASTFM_INCLUDE_DIRS AND LASTFM1_INCLUDE_DIRS)
endif()
if (APPLE)
find_library(GROWL Growl)
find_library(SPARKLE Sparkle)
find_library(SPOTIFY libspotify)

View File

@ -853,7 +853,6 @@ optional_source(HAVE_SPOTIFY_DOWNLOADER
# Platform specific - OS X
optional_source(APPLE
INCLUDE_DIRECTORIES
${GROWL}/Headers
${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/google-breakpad/client/mac/build/Release/Breakpad.framework
SOURCES
core/macfslistener.mm
@ -1290,7 +1289,6 @@ endif()
if (APPLE)
target_link_libraries(clementine_lib
${GROWL}
/System/Library/Frameworks/AppKit.framework
/System/Library/Frameworks/Carbon.framework
/System/Library/Frameworks/CoreAudio.framework
@ -1395,9 +1393,6 @@ if (APPLE)
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/Sparkle.framework")
endif (HAVE_SPARKLE)
install(DIRECTORY "${GROWL}/Versions/Current/Resources"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/Growl.framework")
install(FILES "${QT_QTCORE_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtCore.framework/Contents")
install(FILES "${QT_QTGUI_LIBRARY_RELEASE}/Contents/Info.plist"

View File

@ -20,12 +20,14 @@
#include "libraryquery.h"
#include "groupbydialog.h"
#include "ui_libraryfilterwidget.h"
#include "core/song.h"
#include "ui/iconloader.h"
#include "ui/settingsdialog.h"
#include <QActionGroup>
#include <QKeyEvent>
#include <QMenu>
#include <QRegExp>
#include <QSettings>
#include <QSignalMapper>
#include <QTimer>
@ -39,6 +41,13 @@ LibraryFilterWidget::LibraryFilterWidget(QWidget* parent)
filter_applies_to_model_(true),
delay_behaviour_(DelayedOnLargeLibraries) {
ui_->setupUi(this);
// Add the available fields to the tooltip here instead of the ui
// file to prevent that they get translated by mistake.
QString available_fields =
Song::kFtsColumns.join(", ").replace(QRegExp("\\bfts"), "");
ui_->filter->setToolTip(ui_->filter->toolTip().arg(available_fields));
connect(ui_->filter, SIGNAL(returnPressed()), SIGNAL(ReturnPressed()));
connect(filter_delay_, SIGNAL(timeout()), SLOT(FilterDelayTimeout()));

View File

@ -23,7 +23,7 @@
<item>
<widget class="QSearchField" name="filter" native="true">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Prefix a word with a field name to limit the search to that field, e.g. &lt;span style=&quot; font-weight:600;&quot;&gt;artist:&lt;/span&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Bode&lt;/span&gt; searches the library for all artists that contain the word Bode.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Available fields: &lt;/span&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;title, album, artist, albumartist, composer, performer, grouping, genre, comment&lt;/span&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Prefix a word with a field name to limit the search to that field, e.g. &lt;span style=&quot; font-weight:600;&quot;&gt;artist:&lt;/span&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Bode&lt;/span&gt; searches the library for all artists that contain the word Bode.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Available fields: &lt;/span&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;%1&lt;/span&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="placeholderText" stdset="0">
<string>Enter search terms here</string>

View File

@ -101,7 +101,8 @@ return_song:
}
void XSPFParser::Save(const SongList& songs, QIODevice* device,
const QDir&) const {
const QDir& dir) const {
QFileInfo file;
QXmlStreamWriter writer(device);
writer.setAutoFormatting(true);
writer.setAutoFormattingIndent(2);
@ -112,8 +113,17 @@ void XSPFParser::Save(const SongList& songs, QIODevice* device,
StreamElement tracklist("trackList", &writer);
for (const Song& song : songs) {
QString filename_or_url;
if (song.url().scheme() == "file") {
// Make the filename relative to the directory we're saving the playlist.
filename_or_url = dir.relativeFilePath(
QFileInfo(song.url().toLocalFile()).absoluteFilePath());
} else {
filename_or_url = song.url().toEncoded();
}
StreamElement track("track", &writer);
writer.writeTextElement("location", song.url().toString());
writer.writeTextElement("location", filename_or_url);
writer.writeTextElement("title", song.title());
if (!song.artist().isEmpty()) {
writer.writeTextElement("creator", song.artist());
@ -130,11 +140,24 @@ void XSPFParser::Save(const SongList& songs, QIODevice* device,
song.art_manual().isEmpty() ? song.art_automatic() : song.art_manual();
// Ignore images that are in our resource bundle.
if (!art.startsWith(":") && !art.isEmpty()) {
// Convert local files to URLs.
QString art_filename;
if (!art.contains("://")) {
art = QUrl::fromLocalFile(art).toString();
art_filename = art;
} else if (QUrl(art).scheme() == "file") {
art_filename = QUrl(art).toLocalFile();
}
writer.writeTextElement("image", art);
if (!art_filename.isEmpty()) {
// Make this filename relative to the directory we're saving the
// playlist.
art_filename = dir.relativeFilePath(
QFileInfo(art_filename).absoluteFilePath());
} else {
// Just use whatever URL was in the Song.
art_filename = art;
}
writer.writeTextElement("image", art_filename);
}
}
writer.writeEndDocument();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -296,7 +296,7 @@
<item row="2" column="0">
<widget class="QLabel" name="buffer_min_fill_label">
<property name="text">
<string>Buffer low fill</string>
<string>Minimum buffer fill</string>
</property>
</widget>
</item>

View File

@ -127,11 +127,6 @@ class OSD : public QObject {
QString last_image_uri_;
QImage last_image_;
#ifdef Q_OS_DARWIN
class GrowlNotificationWrapper;
GrowlNotificationWrapper* wrapper_;
#endif // Q_OS_DARWIN
#ifdef HAVE_DBUS
std::unique_ptr<OrgFreedesktopNotificationsInterface> interface_;
uint notification_id_;

View File

@ -22,117 +22,8 @@
#include <QFile>
#include <QtDebug>
#import <GrowlApplicationBridge.h>
#include "core/scoped_nsautorelease_pool.h"
#include "core/scoped_nsobject.h"
@interface GrowlInterface : NSObject<GrowlApplicationBridgeDelegate> {
}
- (void)SendGrowlAlert:(NSString*)message
title:(NSString*)title
image:(NSData*)image;
- (void)ClickCallback; // Called when user clicks on notification.
@end
@implementation GrowlInterface
- (id)init {
if ((self = [super init])) {
[GrowlApplicationBridge setGrowlDelegate:self];
}
return self;
}
- (void)dealloc {
[super dealloc];
}
- (NSDictionary*)registrationDictionaryForGrowl {
NSArray* array = [NSArray
arrayWithObjects:@"next_track", nil]; // Valid notification names.
NSDictionary* dict = [NSDictionary
dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1], @"TicketVersion",
array, @"AllNotifications", array,
@"DefaultNotifications",
@"com.davidsansome.clementine",
@"ApplicationId", nil];
return dict;
}
- (void)growlNotificationWasClicked:(id)clickContext {
if (clickContext) {
[self ClickCallback];
}
return;
}
- (void)SendGrowlAlert:(NSString*)message
title:(NSString*)title
image:(NSData*)image {
[GrowlApplicationBridge
notifyWithTitle:title
description:message
notificationName:@"next_track"
iconData:image
priority:0
isSticky:NO
clickContext:@"click_callback"]; // String sent to our callback.
}
- (void)ClickCallback {
qDebug() << "Growl notification clicked!";
return;
}
@end
class OSD::GrowlNotificationWrapper {
public:
GrowlNotificationWrapper() {
growl_interface_ = [[GrowlInterface alloc] init];
}
~GrowlNotificationWrapper() { [growl_interface_ release]; }
void ShowMessage(const QString& summary, const QString& message,
const QImage& image) {
NSString* mac_message =
[[NSString alloc] initWithUTF8String:message.toUtf8().constData()];
NSString* mac_summary =
[[NSString alloc] initWithUTF8String:summary.toUtf8().constData()];
NSData* image_data = nil;
// Growl expects raw TIFF data.
// This is nasty but it keeps the API nice.
if (!image.isNull()) {
QByteArray tiff_data;
QBuffer tiff(&tiff_data);
image.save(&tiff, "TIFF");
image_data =
[NSData dataWithBytes:tiff_data.constData() length:tiff_data.size()];
}
[growl_interface_ SendGrowlAlert:mac_message
title:mac_summary
image:image_data];
[mac_message release];
[mac_summary release];
}
private:
GrowlInterface* growl_interface_;
ScopedNSAutoreleasePool pool_;
};
void OSD::Init() { wrapper_ = new GrowlNotificationWrapper; }
bool OSD::SupportsNativeNotifications() { return true; }
bool OSD::SupportsTrayPopups() { return false; }
namespace {
bool NotificationCenterSupported() {
@ -152,17 +43,23 @@ void SendNotificationCenterMessage(NSString* title, NSString* subtitle) {
}
}
void OSD::Init() {}
bool OSD::SupportsNativeNotifications() {
return NotificationCenterSupported();
}
bool OSD::SupportsTrayPopups() { return false; }
void OSD::ShowMessageNative(const QString& summary, const QString& message,
const QString& icon, const QImage& image) {
Q_UNUSED(icon);
if (NotificationCenterSupported()) {
scoped_nsobject<NSString> mac_message(
[[NSString alloc] initWithUTF8String:message.toUtf8().constData()]);
scoped_nsobject<NSString> mac_summary(
[[NSString alloc] initWithUTF8String:summary.toUtf8().constData()]);
SendNotificationCenterMessage(mac_summary.get(), mac_message.get());
} else {
wrapper_->ShowMessage(summary, message, image);
}
}