diff --git a/src/libtomahawk/thirdparty/Qocoa/qocoa_mac.h b/src/libtomahawk/thirdparty/Qocoa/qocoa_mac.h index 1b6963d11..ee620a3a5 100644 --- a/src/libtomahawk/thirdparty/Qocoa/qocoa_mac.h +++ b/src/libtomahawk/thirdparty/Qocoa/qocoa_mac.h @@ -30,7 +30,8 @@ THE SOFTWARE. static inline NSString* fromQString(const QString &string) { - char* cString = string.toUtf8().data(); + const QByteArray utf8 = string.toUtf8(); + const char* cString = utf8.constData(); return [[NSString alloc] initWithUTF8String:cString]; } @@ -41,11 +42,17 @@ static inline QString toQString(NSString *string) return QString::fromUtf8([string UTF8String]); } -static inline void zeroLayout(void *cocoaView, QWidget *parent) +static inline NSImage* fromQPixmap(const QPixmap &pixmap) { + CGImageRef cgImage = pixmap.toMacCGImageRef(); + return [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize]; +} + +static inline void setupLayout(void *cocoaView, QWidget *parent) +{ + parent->setAttribute(Qt::WA_NativeWindow); QVBoxLayout *layout = new QVBoxLayout(parent); layout->setMargin(0); - parent->setAttribute(Qt::WA_NativeWindow); layout->addWidget(new QMacCocoaViewContainer(cocoaView, parent)); } diff --git a/src/libtomahawk/thirdparty/Qocoa/qsearchfield.h b/src/libtomahawk/thirdparty/Qocoa/qsearchfield.h index e9371ba96..0b429972f 100644 --- a/src/libtomahawk/thirdparty/Qocoa/qsearchfield.h +++ b/src/libtomahawk/thirdparty/Qocoa/qsearchfield.h @@ -2,6 +2,7 @@ #define QSEARCHFIELD_H #include +#include #include "DllMacro.h" @@ -9,23 +10,34 @@ class QSearchFieldPrivate; class DLLEXPORT QSearchField : public QWidget { Q_OBJECT + + Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText); + public: - explicit QSearchField(QWidget* parent); + explicit QSearchField(QWidget *parent); QString text() const; + QString placeholderText() const; + void setFocus(Qt::FocusReason); public slots: void setText(const QString &text); void setPlaceholderText(const QString& text); - void clear(); + void selectAll(); + void setFocus(); + signals: void textChanged(const QString &text); + void editingFinished(); void returnPressed(); +protected: + void resizeEvent(QResizeEvent*); + private: friend class QSearchFieldPrivate; - QSearchFieldPrivate *pimpl; + QPointer pimpl; }; #endif // QSEARCHFIELD_H diff --git a/src/libtomahawk/thirdparty/Qocoa/qsearchfield_mac.mm b/src/libtomahawk/thirdparty/Qocoa/qsearchfield_mac.mm index efa05f631..40b109849 100644 --- a/src/libtomahawk/thirdparty/Qocoa/qsearchfield_mac.mm +++ b/src/libtomahawk/thirdparty/Qocoa/qsearchfield_mac.mm @@ -30,42 +30,105 @@ THE SOFTWARE. #import "Foundation/NSNotification.h" #import "AppKit/NSSearchField.h" -class QSearchFieldPrivate +#include +#include + +#define KEYCODE_A 0 +#define KEYCODE_X 7 +#define KEYCODE_C 8 +#define KEYCODE_V 9 + +class QSearchFieldPrivate : public QObject { public: QSearchFieldPrivate(QSearchField *qSearchField, NSSearchField *nsSearchField) - : qSearchField(qSearchField), nsSearchField(nsSearchField) {} + : QObject(qSearchField), qSearchField(qSearchField), nsSearchField(nsSearchField) {} void textDidChange(const QString &text) { - emit qSearchField->textChanged(text); + if (qSearchField) + emit qSearchField->textChanged(text); } void textDidEndEditing() { - emit qSearchField->returnPressed(); + if (qSearchField) + emit qSearchField->editingFinished(); } - QSearchField *qSearchField; + void returnPressed() + { + if (qSearchField) + emit qSearchField->returnPressed(); + } + + QPointer qSearchField; NSSearchField *nsSearchField; }; @interface QSearchFieldDelegate : NSObject { @public - QSearchFieldPrivate* pimpl; + QPointer pimpl; } -(void)controlTextDidChange:(NSNotification*)notification; --(void)controlTextDidEndEditing:(NSNotification*)aNotification; +-(void)controlTextDidEndEditing:(NSNotification*)notification; @end @implementation QSearchFieldDelegate -(void)controlTextDidChange:(NSNotification*)notification { - pimpl->textDidChange(toQString([[notification object] stringValue])); + Q_ASSERT(pimpl); + if (pimpl) + pimpl->textDidChange(toQString([[notification object] stringValue])); } -(void)controlTextDidEndEditing:(NSNotification*)notification { - pimpl->textDidEndEditing(); + Q_UNUSED(notification); + // No Q_ASSERT here as it is called on destruction. + if (pimpl) + pimpl->textDidEndEditing(); + + if ([[[notification userInfo] objectForKey:@"NSTextMovement"] intValue] == NSReturnTextMovement) + pimpl->returnPressed(); +} +@end + +@interface QocoaSearchField : NSSearchField +-(BOOL)performKeyEquivalent:(NSEvent*)event; +@end + +@implementation QocoaSearchField +-(BOOL)performKeyEquivalent:(NSEvent*)event { + if ([event type] == NSKeyDown && [event modifierFlags] & NSCommandKeyMask) + { + const unsigned short keyCode = [event keyCode]; + if (keyCode == KEYCODE_A) + { + [self performSelector:@selector(selectText:)]; + return YES; + } + else if (keyCode == KEYCODE_C) + { + QClipboard* clipboard = QApplication::clipboard(); + clipboard->setText(toQString([self stringValue])); + return YES; + } + else if (keyCode == KEYCODE_V) + { + QClipboard* clipboard = QApplication::clipboard(); + [self setStringValue:fromQString(clipboard->text())]; + return YES; + } + else if (keyCode == KEYCODE_X) + { + QClipboard* clipboard = QApplication::clipboard(); + clipboard->setText(toQString([self stringValue])); + [self setStringValue:@""]; + return YES; + } + } + + return NO; } @end @@ -73,27 +136,30 @@ QSearchField::QSearchField(QWidget *parent) : QWidget(parent) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSSearchField *search = [[NSSearchField alloc] init]; - pimpl = new QSearchFieldPrivate(this, search); + NSSearchField *search = [[QocoaSearchField alloc] init]; QSearchFieldDelegate *delegate = [[QSearchFieldDelegate alloc] init]; - delegate->pimpl = pimpl; + pimpl = delegate->pimpl = new QSearchFieldPrivate(this, search); [search setDelegate:delegate]; - zeroLayout(search, this); + setupLayout(search, this); + + setFixedHeight(24); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); layout()->setContentsMargins(2, 0, 2, 0); setStyleSheet( "* { background: #DDE4EB; }" ); - setMinimumSize(layout()->sizeHint().width(), 20); - [search release]; [pool drain]; } void QSearchField::setText(const QString &text) { + Q_ASSERT(pimpl); + if (!pimpl) + return; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [pimpl->nsSearchField setStringValue:fromQString(text)]; [pool drain]; @@ -101,6 +167,10 @@ void QSearchField::setText(const QString &text) void QSearchField::setPlaceholderText(const QString& text) { + Q_ASSERT(pimpl); + if (!pimpl) + return; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [[pimpl->nsSearchField cell] setPlaceholderString:fromQString(text)]; [pool drain]; @@ -108,10 +178,57 @@ void QSearchField::setPlaceholderText(const QString& text) void QSearchField::clear() { + Q_ASSERT(pimpl); + if (!pimpl) + return; + [pimpl->nsSearchField setStringValue:@""]; + emit textChanged(QString()); +} + +void QSearchField::selectAll() +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + [pimpl->nsSearchField performSelector:@selector(selectText:)]; } QString QSearchField::text() const { + Q_ASSERT(pimpl); + if (!pimpl) + return QString(); + return toQString([pimpl->nsSearchField stringValue]); } + +QString QSearchField::placeholderText() const +{ + Q_ASSERT(pimpl); + if (!pimpl) + return QString(); + + return toQString([[pimpl->nsSearchField cell] placeholderString]); +} + +void QSearchField::setFocus(Qt::FocusReason reason) +{ + Q_ASSERT(pimpl); + if (!pimpl) + return; + + if ([pimpl->nsSearchField acceptsFirstResponder]) + [[pimpl->nsSearchField window] makeFirstResponder: pimpl->nsSearchField]; +} + +void QSearchField::setFocus() +{ + setFocus(Qt::OtherFocusReason); +} + +void QSearchField::resizeEvent(QResizeEvent *resizeEvent) +{ + QWidget::resizeEvent(resizeEvent); +}