source: trunk/src/gui/dialogs/qfontdialog_mac.mm@ 564

Last change on this file since 564 was 561, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 21.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qfontdialog_p.h"
43#if !defined(QT_NO_FONTDIALOG) && defined(Q_WS_MAC)
44#include <qapplication.h>
45#include <qdialogbuttonbox.h>
46#include <qlineedit.h>
47#include <private/qapplication_p.h>
48#include <private/qfont_p.h>
49#include <private/qfontengine_p.h>
50#include <private/qt_cocoa_helpers_mac_p.h>
51#include <private/qt_mac_p.h>
52#include <qdebug.h>
53#import <AppKit/AppKit.h>
54#import <Foundation/Foundation.h>
55
56#if !CGFLOAT_DEFINED
57typedef float CGFloat; // Should only not be defined on 32-bit platforms
58#endif
59
60QT_USE_NAMESPACE
61
62// should a priori be kept in sync with qcolordialog_mac.mm
63const CGFloat ButtonMinWidth = 78.0;
64const CGFloat ButtonMinHeight = 32.0;
65const CGFloat ButtonSpacing = 0.0;
66const CGFloat ButtonTopMargin = 0.0;
67const CGFloat ButtonBottomMargin = 7.0;
68const CGFloat ButtonSideMargin = 9.0;
69
70// looks better with some margins
71const CGFloat DialogTopMargin = 7.0;
72const CGFloat DialogSideMargin = 9.0;
73
74const int StyleMask = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
75
76@class QCocoaFontPanelDelegate;
77
78
79#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
80
81@protocol NSWindowDelegate <NSObject>
82- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize;
83@end
84
85#endif
86
87@interface QCocoaFontPanelDelegate : NSObject <NSWindowDelegate> {
88 NSFontPanel *mFontPanel;
89 NSView *mStolenContentView;
90 NSButton *mOkButton;
91 NSButton *mCancelButton;
92 QFontDialogPrivate *mPriv;
93 QFont *mQtFont;
94 BOOL mPanelHackedWithButtons;
95 CGFloat mDialogExtraWidth;
96 CGFloat mDialogExtraHeight;
97 NSModalSession mModalSession;
98}
99- (id)initWithFontPanel:(NSFontPanel *)panel
100 stolenContentView:(NSView *)stolenContentView
101 okButton:(NSButton *)okButton
102 cancelButton:(NSButton *)cancelButton
103 priv:(QFontDialogPrivate *)priv
104 extraWidth:(CGFloat)extraWidth
105 extraHeight:(CGFloat)extraHeight;
106- (void)changeFont:(id)sender;
107- (void)changeAttributes:(id)sender;
108- (void)setModalSession:(NSModalSession)session;
109- (BOOL)windowShouldClose:(id)window;
110- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize;
111- (void)relayout;
112- (void)relayoutToContentSize:(NSSize)frameSize;
113- (void)onOkClicked;
114- (void)onCancelClicked;
115- (NSFontPanel *)fontPanel;
116- (NSWindow *)actualPanel;
117- (NSSize)dialogExtraSize;
118- (void)setQtFont:(const QFont &)newFont;
119- (QFont)qtFont;
120- (void)finishOffWithCode:(NSInteger)result;
121- (void)cleanUpAfterMyself;
122@end
123
124static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont)
125{
126 QFont newFont;
127 if (cocoaFont) {
128 int pSize = qRound([cocoaFont pointSize]);
129 QString family(qt_mac_NSStringToQString([cocoaFont familyName]));
130 QString typeface(qt_mac_NSStringToQString([cocoaFont fontName]));
131
132 int hyphenPos = typeface.indexOf(QLatin1Char('-'));
133 if (hyphenPos != -1) {
134 typeface.remove(0, hyphenPos + 1);
135 } else {
136 typeface = QLatin1String("Normal");
137 }
138
139 newFont = QFontDatabase().font(family, typeface, pSize);
140 newFont.setUnderline(resolveFont.underline());
141 newFont.setStrikeOut(resolveFont.strikeOut());
142
143 }
144 return newFont;
145}
146
147@implementation QCocoaFontPanelDelegate
148- (id)initWithFontPanel:(NSFontPanel *)panel
149 stolenContentView:(NSView *)stolenContentView
150 okButton:(NSButton *)okButton
151 cancelButton:(NSButton *)cancelButton
152 priv:(QFontDialogPrivate *)priv
153 extraWidth:(CGFloat)extraWidth
154 extraHeight:(CGFloat)extraHeight
155{
156 self = [super init];
157 mFontPanel = panel;
158 mStolenContentView = stolenContentView;
159 mOkButton = okButton;
160 mCancelButton = cancelButton;
161 mPriv = priv;
162 mPanelHackedWithButtons = (okButton != 0);
163 mDialogExtraWidth = extraWidth;
164 mDialogExtraHeight = extraHeight;
165 mModalSession = 0;
166
167 if (mPanelHackedWithButtons) {
168 [self relayout];
169
170 [okButton setAction:@selector(onOkClicked)];
171 [okButton setTarget:self];
172
173 [cancelButton setAction:@selector(onCancelClicked)];
174 [cancelButton setTarget:self];
175 }
176 mQtFont = new QFont();
177 return self;
178}
179
180- (void)dealloc
181{
182 delete mQtFont;
183 [super dealloc];
184}
185
186- (void)changeFont:(id)sender
187{
188 NSFont *dummyFont = [NSFont userFontOfSize:12.0];
189 [self setQtFont:qfontForCocoaFont([sender convertFont:dummyFont], *mQtFont)];
190 if (mPriv)
191 mPriv->updateSampleFont(*mQtFont);
192}
193
194- (void)changeAttributes:(id)sender
195{
196 NSDictionary *dummyAttribs = [NSDictionary dictionary];
197 NSDictionary *attribs = [sender convertAttributes:dummyAttribs];
198
199#ifdef QT_MAC_USE_COCOA
200 for (id key in attribs) {
201#else
202 NSEnumerator *enumerator = [attribs keyEnumerator];
203 id key;
204 while((key = [enumerator nextObject])) {
205#endif
206 NSNumber *number = static_cast<NSNumber *>([attribs objectForKey:key]);
207 if ([key isEqual:NSUnderlineStyleAttributeName]) {
208 mQtFont->setUnderline([number intValue] != NSUnderlineStyleNone);
209 } else if ([key isEqual:NSStrikethroughStyleAttributeName]) {
210 mQtFont->setStrikeOut([number intValue] != NSUnderlineStyleNone);
211 }
212 }
213
214 if (mPriv)
215 mPriv->updateSampleFont(*mQtFont);
216}
217
218- (void)setModalSession:(NSModalSession)session
219{
220 Q_ASSERT(!mModalSession);
221 mModalSession = session;
222}
223
224- (BOOL)windowShouldClose:(id)window
225{
226 Q_UNUSED(window);
227 if (mPanelHackedWithButtons) {
228 [self onCancelClicked];
229 } else {
230 [self finishOffWithCode:NSCancelButton];
231 }
232 return true;
233}
234
235- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
236{
237 if (mFontPanel == window) {
238 proposedFrameSize = [static_cast<id <NSWindowDelegate> >(mFontPanel) windowWillResize:mFontPanel toSize:proposedFrameSize];
239 } else {
240 /*
241 Ugly hack: NSFontPanel rearranges the layout of its main
242 component in windowWillResize:toSize:. So we temporarily
243 restore the stolen content view to its rightful owner,
244 call windowWillResize:toSize:, and steal the content view
245 again.
246 */
247 [mStolenContentView removeFromSuperview];
248 [mFontPanel setContentView:mStolenContentView];
249 NSSize extraSize = [self dialogExtraSize];
250 proposedFrameSize.width -= extraSize.width;
251 proposedFrameSize.height -= extraSize.height;
252 proposedFrameSize = [static_cast<id <NSWindowDelegate> >(mFontPanel) windowWillResize:mFontPanel toSize:proposedFrameSize];
253 NSRect frameRect = { { 0.0, 0.0 }, proposedFrameSize };
254 [mFontPanel setFrame:frameRect display:NO];
255 [mFontPanel setContentView:0];
256 [[window contentView] addSubview:mStolenContentView];
257 proposedFrameSize.width += extraSize.width;
258 proposedFrameSize.height += extraSize.height;
259 }
260 if (mPanelHackedWithButtons) {
261 NSRect frameRect = { { 0.0, 0.0 }, proposedFrameSize };
262 NSRect contentRect = [NSWindow contentRectForFrameRect:frameRect styleMask:[window styleMask]];
263 [self relayoutToContentSize:contentRect.size];
264 }
265 return proposedFrameSize;
266}
267
268- (void)relayout
269{
270 [self relayoutToContentSize:[[mStolenContentView superview] frame].size];
271}
272
273- (void)relayoutToContentSize:(NSSize)frameSize;
274{
275 Q_ASSERT(mPanelHackedWithButtons);
276
277 [mOkButton sizeToFit];
278 NSSize okSizeHint = [mOkButton frame].size;
279
280 [mCancelButton sizeToFit];
281 NSSize cancelSizeHint = [mCancelButton frame].size;
282
283 const CGFloat ButtonWidth = qMin(qMax(ButtonMinWidth,
284 qMax(okSizeHint.width, cancelSizeHint.width)),
285 CGFloat((frameSize.width - 2.0 * ButtonSideMargin
286 - ButtonSpacing) * 0.5));
287 const CGFloat ButtonHeight = qMax(ButtonMinHeight,
288 qMax(okSizeHint.height, cancelSizeHint.height));
289
290 const CGFloat X = DialogSideMargin;
291 const CGFloat Y = ButtonBottomMargin + ButtonHeight + ButtonTopMargin;
292
293 NSRect okRect = { { frameSize.width - ButtonSideMargin - ButtonWidth,
294 ButtonBottomMargin },
295 { ButtonWidth, ButtonHeight } };
296 [mOkButton setFrame:okRect];
297 [mOkButton setNeedsDisplay:YES];
298
299 NSRect cancelRect = { { okRect.origin.x - ButtonSpacing - ButtonWidth,
300 ButtonBottomMargin },
301 { ButtonWidth, ButtonHeight } };
302 [mCancelButton setFrame:cancelRect];
303 [mCancelButton setNeedsDisplay:YES];
304
305 NSRect stolenCVRect = { { X, Y },
306 { frameSize.width - X - X, frameSize.height - Y - DialogTopMargin } };
307 [mStolenContentView setFrame:stolenCVRect];
308 [mStolenContentView setNeedsDisplay:YES];
309
310 [[mStolenContentView superview] setNeedsDisplay:YES];
311}
312
313- (void)onOkClicked
314{
315 Q_ASSERT(mPanelHackedWithButtons);
316 NSFontManager *fontManager = [NSFontManager sharedFontManager];
317 [self setQtFont:qfontForCocoaFont([fontManager convertFont:[fontManager selectedFont]],
318 *mQtFont)];
319 [[mStolenContentView window] close];
320 [self finishOffWithCode:NSOKButton];
321}
322
323- (void)onCancelClicked
324{
325 Q_ASSERT(mPanelHackedWithButtons);
326 [[mStolenContentView window] close];
327 [self finishOffWithCode:NSCancelButton];
328}
329
330- (NSFontPanel *)fontPanel
331{
332 return mFontPanel;
333}
334
335- (NSWindow *)actualPanel
336{
337 return [mStolenContentView window];
338}
339
340- (NSSize)dialogExtraSize
341{
342 // this must be recomputed each time, because sometimes the
343 // NSFontPanel has the NSDocModalWindowMask flag set, and sometimes
344 // not -- which affects the frame rect vs. content rect measurements
345
346 // take the different frame rectangles into account for dialogExtra{Width,Height}
347 NSRect someRect = { { 0.0, 0.0 }, { 100000.0, 100000.0 } };
348 NSRect sharedFontPanelContentRect = [mFontPanel contentRectForFrameRect:someRect];
349 NSRect ourPanelContentRect = [NSWindow contentRectForFrameRect:someRect styleMask:StyleMask];
350
351 NSSize result = { mDialogExtraWidth, mDialogExtraHeight };
352 result.width -= ourPanelContentRect.size.width - sharedFontPanelContentRect.size.width;
353 result.height -= ourPanelContentRect.size.height - sharedFontPanelContentRect.size.height;
354 return result;
355}
356
357- (void)setQtFont:(const QFont &)newFont
358{
359 delete mQtFont;
360 mQtFont = new QFont(newFont);
361}
362
363- (QFont)qtFont
364{
365 return *mQtFont;
366}
367
368- (void)finishOffWithCode:(NSInteger)code
369{
370 if (mPriv) {
371 if (mModalSession) {
372 [NSApp endModalSession:mModalSession];
373 mModalSession = 0;
374 }
375
376 mPriv->done((code == NSOKButton) ? QDialog::Accepted : QDialog::Rejected);
377 } else {
378 [NSApp stopModalWithCode:code];
379 }
380}
381
382- (void)cleanUpAfterMyself
383{
384 if (mPanelHackedWithButtons) {
385 NSView *ourContentView = [mFontPanel contentView];
386
387 // return stolen stuff to its rightful owner
388 [mStolenContentView removeFromSuperview];
389 [mFontPanel setContentView:mStolenContentView];
390
391 [mOkButton release];
392 [mCancelButton release];
393 [ourContentView release];