forked from rentzsch/Blitz
-
Notifications
You must be signed in to change notification settings - Fork 2
/
MyDocument.m
244 lines (202 loc) · 9.95 KB
/
MyDocument.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#import "MyDocument.h"
#import "SlidesWindowController.h"
#import "SpeakerNotesWindowController.h"
#import "BlitzPDFView.h"
@interface NSObject (UndocumentedQuickLookUI)
- (id)_previewView; // -[QLPreviewPanelController _previewView]
- (id)displayBundle; // -[QLPreviewView displayBundle];
- (PDFDocument*)pdfDocument; // -[QLPDFDisplayBundle pdfDocument]
@end
@interface MyDocument ()
@property (retain, nonatomic) PDFDocument *pdfDocument;
@property (retain, nonatomic) NSTimer *timer;
@property (nonatomic) BOOL isInFullScreenMode;
@property(assign) NSTimeInterval secondsElapsed;
@property(assign,readwrite) BOOL running;
@end
@implementation MyDocument
@synthesize pdfDocument, timer, isInFullScreenMode, secondsElapsed, running;
@synthesize pageIndex;
- (void)toggleFullScreenMode {
SlidesWindowController *slides = [self.windowControllers objectAtIndex:0];
SpeakerNotesWindowController *notes = [self.windowControllers objectAtIndex:1];
NSView *slidesView = slides.pdfView;
NSView *notesView = notes.window.contentView;
if (self.isInFullScreenMode) {
[slidesView exitFullScreenModeWithOptions:nil];
[notesView exitFullScreenModeWithOptions:nil];
self.isInFullScreenMode = NO;
} else {
// Notes are on the MacBook Pro main screen at 1920x1200, slides are on the projector at 1280x720.
// For now, assuming that we don't need to change display resolutions and that these will be the only two displays and that the main screen will be the one for the notes.
// Screen with menu bar is screen 0, not mainScreen
// See: http://stackoverflow.com/questions/1512761/making-a-full-screen-cocoa-app
NSScreen *notesScreen = [[NSScreen screens] objectAtIndex:0];
NSScreen *slidesScreen = nil;
for (NSScreen *screen in [NSScreen screens]) {
if (screen != notesScreen) {
slidesScreen = screen;
break;
}
}
if (!notesScreen || !slidesScreen) {
NSInteger rc = NSRunAlertPanel(@"Missing a screen", @"Unable to find both a note and slide screen", @"Cancel", @"Run Slides", nil);
if (rc == NSAlertDefaultReturn)
return;
slidesScreen = [[NSScreen screens] objectAtIndex:0];
notesScreen = nil;
}
if (notesScreen) {
//NSLog(@"notes %@ on %@ %@", notes, notesScreen, NSStringFromRect([notesScreen frame]));
[notesView enterFullScreenMode:notesScreen withOptions:nil];
}
//NSLog(@"slides %@ on %@ %@", slides, slidesScreen, NSStringFromRect([slidesScreen frame]));
[slidesView enterFullScreenMode:slidesScreen withOptions:nil];
[NSCursor setHiddenUntilMouseMoves:YES];
self.isInFullScreenMode = YES;
}
}
- (void)initPDFView {
self.isInFullScreenMode = NO;
[self toggleFullScreenMode];
}
- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError {
//return [self.pdfDocument writeToURL:absoluteURL];
[self doesNotRecognizeSelector:_cmd]; // Renounce writing the PDF to disk.
return NO;
}
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5
- (void)pollPDFPageCount:(NSTimer*)timer_ {
id myQLPreviewPanelController = [[QLPreviewPanel sharedPreviewPanel] windowController];
//NSLog(@"myQLPreviewPanelController: %@", myQLPreviewPanelController);
id myQLPreviewView = [myQLPreviewPanelController _previewView];
//NSLog(@"myQLPreviewView: %@", myQLPreviewView);
id myQLDisplayBundle = [myQLPreviewView displayBundle];
//NSLog(@"myQLDisplayBundle: %@", myQLDisplayBundle);
if (![myQLDisplayBundle respondsToSelector:@selector(pdfDocument)]) {
// It's probably not actually a QLPDFDisplayBundle -- bail.
[timer_ invalidate];
NSRunCriticalAlertPanel(@"Couldn't Load Keynote PDF QuickLook Representation",
@"Please ensure the iWork '09's iWork.qlgenerator is installed in /Library/QuickLook.",
nil,
nil,
nil);
[self close];
return;
}
PDFDocument *pdfDisplayBundlePDFDocument = [myQLDisplayBundle pdfDocument];
//[pdfDisplayBundlePDFDocument writeToFile:@"/tmp/key.pdf"];
//NSLog(@"pdfDisplayBundlePDFDocument: %@", pdfDisplayBundlePDFDocument);
//NSLog(@"pageCount: %d", [pdfDisplayBundlePDFDocument pageCount]);
if ([pdfDisplayBundlePDFDocument pageCount] >= 20) {
[timer_ invalidate];
self.pdfDocument = pdfDisplayBundlePDFDocument;
[self initPDFView];
[[QLPreviewPanel sharedPreviewPanel] orderOut:nil];
}
}
#endif
- (BOOL)readFromURL:(NSURL *)initWithURL ofType:(NSString *)typeName error:(NSError **)outError {
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5
if ([[NSWorkspace sharedWorkspace] type:typeName conformsToType:@"com.adobe.pdf"]) {
if (!(self.pdfDocument = [[PDFDocument alloc] initWithURL:initWithURL]))
return NO;
// Can't just -initPDFView here since the window controller's aren't loaded. Keynote path gets away with it due to the timer, so...
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(initPDFView)
userInfo:nil
repeats:NO];
return YES;
} else if ([typeName isEqualToString:@"KeynoteDocument"]) {
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
// Poor man's window-hiding since we can't immediately orderOut the panel (crashes):
[[QLPreviewPanel sharedPreviewPanel] setFrameTopLeftPoint:NSMakePoint(-5000, -5000)];
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(pollPDFPageCount:)
userInfo:nil
repeats:YES];
return YES;
}
else {
return NO;
}
#else
// Note: Could check typename here, but sometimes it comes back com.adobe.pdf
self.pdfDocument = [[PDFDocument alloc] initWithURL:initWithURL];
return self.pdfDocument ? YES : NO;
#endif
}
- (void)updateElapsedTimer:(NSTimer*)timer_ {
if (self.secondsElapsed != 0 && ((int)floor(UPDATES_PER_SECOND * self.secondsElapsed) % (UPDATES_PER_SECOND * SECONDS_PER_SLIDE) == 0)) {
// Triggers page change in associated speaker notes window controller
self.pageIndex++;
if (self.pageIndex >= pdfDocument.pageCount) {
self.running = NO;
[timer_ invalidate];
}
}
self.secondsElapsed += 1.0 / UPDATES_PER_SECOND;
}
- (void)makeWindowControllers;
{
// Slides
{
SlidesWindowController *slides = [[SlidesWindowController alloc] initWithWindowNibName:@"Slides"];
[self addWindowController:slides];
[slides release];
}
// Extract the notes from the Keynote file, if possoble, and converting to HTML. Duct tape and bailing wire.
NSData *htmlData = nil;
NSURL *fileURL = [self fileURL];
NSString *filePath = [fileURL path];
// If opening the .pdf file, open adjacent .key file instead
if ([[filePath pathExtension] isEqual:@"pdf"])
{
filePath = [[filePath stringByDeletingPathExtension] stringByAppendingPathExtension:@"key"];
}
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSString *xslPath = [[NSBundle mainBundle] pathForResource:@"presenter-notes" ofType:@"xsl"];
// CDATA wrapping that xsltproc adds seems to mess up the Javascript, so remove it.
NSString *command = [NSString stringWithFormat:@"/usr/bin/unzip -p '%s' index.apxl | xsltproc '%s' - | sed -e 's/<!\\[CDATA\\[//' -e 's/]]>//'",
[[NSFileManager defaultManager] fileSystemRepresentationWithPath:filePath],
[[NSFileManager defaultManager] fileSystemRepresentationWithPath:xslPath]];
NSTask *task = [[[NSTask alloc] init] autorelease];
NSPipe *pipe = [NSPipe pipe];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObjects:@"-c", command, nil]];
[task setStandardInput:[NSFileHandle fileHandleWithNullDevice]];
[task setStandardOutput:[pipe fileHandleForWriting]];
[task launch];
[[pipe fileHandleForWriting] closeFile]; // have to close our copy of the writing endpoint or we won't get EOF when reading.
htmlData = [[pipe fileHandleForReading] readDataToEndOfFile];
[task waitUntilExit];
//NSLog(@"html = %@", [[[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding] autorelease]);
}
// Load up the speaker notes, UI. Won't have any actual _notes_ unless we are reading a Keynote file.
{
SpeakerNotesWindowController *speakerNotes = [[SpeakerNotesWindowController alloc] initWithHTMLData:htmlData];
[self addWindowController:speakerNotes];
// Don't -showWindow: since that'll make us key; the main window needs to stay key so that the QuickLook hack will work.
[[speakerNotes window] orderBack:nil];
[speakerNotes release];
}
}
- (void)dealloc {
self.pdfDocument = nil;
[self.timer invalidate];
self.timer = nil;
[super dealloc];
}
- (IBAction)start:(id)sender;
{
self.running = YES;
self.secondsElapsed = 0.0;
self.timer = [[NSTimer scheduledTimerWithTimeInterval:1.0 / UPDATES_PER_SECOND
target:self
selector:@selector(updateElapsedTimer:)
userInfo:nil
repeats:YES] retain];
}
@end