PageRenderTime 223ms CodeModel.GetById 151ms app.highlight 2ms RepoModel.GetById 68ms app.codeStats 0ms

/src/libtomahawk/thirdparty/Qocoa/qsearchfield_mac.mm

http://github.com/tomahawk-player/tomahawk
Objective C++ | 294 lines | 219 code | 51 blank | 24 comment | 43 complexity | 25830b68713bc6f97f504885eb11cfcc MD5 | raw file
  1/*
  2Copyright (C) 2011 by Mike McQuaid
  3
  4Permission is hereby granted, free of charge, to any person obtaining a copy
  5of this software and associated documentation files (the "Software"), to deal
  6in the Software without restriction, including without limitation the rights
  7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8copies of the Software, and to permit persons to whom the Software is
  9furnished to do so, subject to the following conditions:
 10
 11The above copyright notice and this permission notice shall be included in
 12all copies or substantial portions of the Software.
 13
 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20THE SOFTWARE.
 21*/
 22
 23#include "qsearchfield.h"
 24#include "moc_qsearchfield.cpp"
 25
 26#include "qocoa_mac.h"
 27
 28#import "Foundation/NSAutoreleasePool.h"
 29#import "Foundation/NSNotification.h"
 30#import "AppKit/NSSearchField.h"
 31
 32#include <QApplication>
 33#include <QKeyEvent>
 34#include <QClipboard>
 35
 36class QSearchFieldPrivate : public QObject
 37{
 38public:
 39    QSearchFieldPrivate(QSearchField *qSearchField, NSSearchField *nsSearchField)
 40        : QObject(qSearchField), qSearchField(qSearchField), nsSearchField(nsSearchField) {}
 41
 42    void textDidChange(const QString &text)
 43    {
 44        if (qSearchField)
 45            emit qSearchField->textChanged(text);
 46    }
 47
 48    void textDidEndEditing()
 49    {
 50        if (qSearchField)
 51            emit qSearchField->editingFinished();
 52    }
 53
 54    void returnPressed()
 55    {
 56        if (qSearchField) {
 57            emit qSearchField->returnPressed();
 58            QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
 59            QApplication::postEvent(qSearchField, event);
 60        }
 61    }
 62
 63    void keyDownPressed()
 64    {
 65        if (qSearchField) {
 66            QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);
 67            QApplication::postEvent(qSearchField, event);
 68        }
 69    }
 70
 71    void keyUpPressed()
 72    {
 73        if (qSearchField) {
 74            QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
 75            QApplication::postEvent(qSearchField, event);
 76        }
 77    }
 78
 79    QPointer<QSearchField> qSearchField;
 80    NSSearchField *nsSearchField;
 81};
 82
 83@interface QSearchFieldDelegate : NSObject<NSTextFieldDelegate>
 84{
 85@public
 86    QPointer<QSearchFieldPrivate> pimpl;
 87}
 88-(void)controlTextDidChange:(NSNotification*)notification;
 89-(void)controlTextDidEndEditing:(NSNotification*)notification;
 90@end
 91
 92@implementation QSearchFieldDelegate
 93-(void)controlTextDidChange:(NSNotification*)notification {
 94    Q_ASSERT(pimpl);
 95    if (pimpl)
 96        pimpl->textDidChange(toQString([[notification object] stringValue]));
 97}
 98
 99-(void)controlTextDidEndEditing:(NSNotification*)notification {
100    Q_UNUSED(notification);
101    // No Q_ASSERT here as it is called on destruction.
102    if (pimpl)
103        pimpl->textDidEndEditing();
104
105    if ([[[notification userInfo] objectForKey:@"NSTextMovement"] intValue] == NSReturnTextMovement)
106        pimpl->returnPressed();
107}
108
109-(BOOL)control: (NSControl *)control textView:
110        (NSTextView *)textView doCommandBySelector:
111        (SEL)commandSelector {
112    Q_ASSERT(pimpl);
113    if (!pimpl) return NO;
114
115    if (commandSelector == @selector(moveDown:)) {
116        pimpl->keyDownPressed();
117        return YES;
118    } else if (commandSelector == @selector(moveUp:)) {
119        pimpl->keyUpPressed();
120        return YES;
121    }
122    return NO;
123}
124
125@end
126
127@interface QocoaSearchField : NSSearchField
128-(BOOL)performKeyEquivalent:(NSEvent*)event;
129@end
130
131@implementation QocoaSearchField
132-(BOOL)performKeyEquivalent:(NSEvent*)event {
133    // First, check if we have the focus.
134    // If no, it probably means this event isn't for us.
135    NSResponder* firstResponder = [[NSApp keyWindow] firstResponder];
136    if ([firstResponder isKindOfClass:[NSText class]] &&
137            [(NSText*)firstResponder delegate] == self) {
138
139        if ([event type] == NSKeyDown && [event modifierFlags] & NSCommandKeyMask)
140        {
141            QString keyString = toQString([event characters]);
142            if (keyString == "a")  // Cmd+a
143            {
144                [self performSelector:@selector(selectText:)];
145                return YES;
146            }
147            else if (keyString == "c")  // Cmd+c
148            {
149                [[self currentEditor] copy: nil];
150                return YES;
151            }
152            else if (keyString == "v")  // Cmd+v
153            {
154                [[self currentEditor] paste: nil];
155                return YES;
156            }
157            else if (keyString == "x")  // Cmd+x
158            {
159                [[self currentEditor] cut: nil];
160                return YES;
161            }
162        }
163    }
164
165    return NO;
166}
167@end
168
169QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
170{
171    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
172
173    NSSearchField *search = [[QocoaSearchField alloc] init];
174
175    QSearchFieldDelegate *delegate = [[QSearchFieldDelegate alloc] init];
176    pimpl = delegate->pimpl = new QSearchFieldPrivate(this, search);
177    [search setDelegate:delegate];
178
179    setupLayout(search, this);
180
181    setFixedHeight(24);
182    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
183
184    [search release];
185
186    [pool drain];
187}
188
189void QSearchField::setMenu(QMenu *menu)
190{
191    Q_ASSERT(pimpl);
192    if (!pimpl)
193        return;
194
195    NSMenu *nsMenu = menu->toNSMenu();
196
197    [[pimpl->nsSearchField cell] setSearchMenuTemplate:nsMenu];
198}
199
200void QSearchField::popupMenu()
201{
202}
203
204void QSearchField::setText(const QString &text)
205{
206    Q_ASSERT(pimpl);
207    if (!pimpl)
208        return;
209
210    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
211    [pimpl->nsSearchField setStringValue:fromQString(text)];
212    [pool drain];
213}
214
215void QSearchField::setPlaceholderText(const QString &text)
216{
217    Q_ASSERT(pimpl);
218    if (!pimpl)
219        return;
220
221    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
222    [[pimpl->nsSearchField cell] setPlaceholderString:fromQString(text)];
223    [pool drain];
224}
225
226void QSearchField::clear()
227{
228    Q_ASSERT(pimpl);
229    if (!pimpl)
230        return;
231
232    [pimpl->nsSearchField setStringValue:@""];
233    emit textChanged(QString());
234}
235
236void QSearchField::selectAll()
237{
238    Q_ASSERT(pimpl);
239    if (!pimpl)
240        return;
241
242    [pimpl->nsSearchField performSelector:@selector(selectText:)];
243}
244
245QString QSearchField::text() const
246{
247    Q_ASSERT(pimpl);
248    if (!pimpl)
249        return QString();
250
251    return toQString([pimpl->nsSearchField stringValue]);
252}
253
254QString QSearchField::placeholderText() const
255{
256    Q_ASSERT(pimpl);
257    if (!pimpl)
258        return QString();
259
260    return toQString([[pimpl->nsSearchField cell] placeholderString]);
261}
262
263void QSearchField::setFocus(Qt::FocusReason)
264{
265    Q_ASSERT(pimpl);
266    if (!pimpl)
267        return;
268
269    if ([pimpl->nsSearchField acceptsFirstResponder])
270        [[pimpl->nsSearchField window] makeFirstResponder: pimpl->nsSearchField];
271}
272
273void QSearchField::setFocus()
274{
275    setFocus(Qt::OtherFocusReason);
276}
277
278void QSearchField::changeEvent(QEvent* event)
279{
280    if (event->type() == QEvent::EnabledChange) {
281        Q_ASSERT(pimpl);
282        if (!pimpl)
283            return;
284
285        const bool enabled = isEnabled();
286        [pimpl->nsSearchField setEnabled: enabled];
287    }
288    QWidget::changeEvent(event);
289}
290
291void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
292{
293    QWidget::resizeEvent(resizeEvent);
294}