kpresenter

KPrMSPresentationSetup.cpp
1/* This file is part of the KDE project
2 Copyright 2004 Brad Hards <bradh@frogmouth.net>
3 Loosely based on webpresention.cpp, which is:
4 Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
5 Copyright 2001, 2002 Nicolas GOUTTE <goutte@kde.org>
6 Copyright 2002 Ariya Hidayat <ariya@kde.org>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22*/
23
24#include "KPrMSPresentationSetup.h"
25
26#include "KPrView.h"
27#include "KPrDocument.h"
28
29#include "KPrCanvas.h"
30#include "KPrPage.h"
31
32#include <tdeio/netaccess.h>
33#include <tdetempfile.h>
34
35#include <tqdir.h>
36#include <tqframe.h>
37#include <tqfileinfo.h>
38#include <tqhbox.h>
39#include <tqlabel.h>
40#include <tqlayout.h>
41#include <tqpixmap.h>
42#include <tqpainter.h>
43#include <tqpushbutton.h>
44#include <tqvbox.h>
45#include <tqwhatsthis.h>
46
47#include <tdeapplication.h>
48#include <kbuttonbox.h>
49#include <kcolorbutton.h>
50#include <tdeglobal.h>
51#include <tdeglobalsettings.h>
52#include <klineedit.h>
53#include <tdelocale.h>
54#include <tdemessagebox.h>
55#include <kprogress.h>
56#include <kstandarddirs.h>
57#include <kurlrequester.h>
58#include <kstdguiitem.h>
59#include <kpushbutton.h>
60
61KPrMSPresentation::KPrMSPresentation( KPrDocument *_doc, KPrView *_view )
62{
63 doc = _doc;
64 view = _view;
65 init();
66}
67
68KPrMSPresentation::KPrMSPresentation( const KPrMSPresentation &msPres )
69 : title( msPres.title ),
70 slideInfos( msPres.slideInfos ), backColour( msPres.backColour ),
71 textColour( msPres.textColour ), path( msPres.path )
72{
73 doc = msPres.doc;
74 view = msPres.view;
75}
76
77void KPrMSPresentation::initCreation( KProgress *progressBar )
78{
79 int p;
80
81 // the title images, and the subsequent real images need to
82 // be in a file under DCIM/, and they start at 101MSPJP, so
83 // we create the DCIM file, and then iterate through looking
84 // for the next "available" directory slot
85 KURL str( path + "/DCIM" );
86 TDEIO::NetAccess::mkdir( str,( TQWidget* )0L );
87
88 p = progressBar->progress();
89 progressBar->setProgress( ++p );
90 kapp->processEvents();
91
92 for (int dirNum = 101; dirNum < 999; dirNum++) {
93 slidePath = TQString("/DCIM/%1MSPJP").arg(dirNum);
94 if (! TDEIO::NetAccess::exists(( path + slidePath), true, ( TQWidget* )0L) )
95 break;
96 }
97
98 p = progressBar->progress();
99 progressBar->setProgress( ++p );
100 kapp->processEvents();
101
102 str = ( path + slidePath );
103 TDEIO::NetAccess::mkdir( str,( TQWidget* )0L );
104 p = progressBar->progress();
105 progressBar->setProgress( ++p );
106 kapp->processEvents();
107
108 // now do the SPP file directory
109 str = ( path + "/MSSONY" );
110 TDEIO::NetAccess::mkdir( str,( TQWidget* )0L );
111
112 p = progressBar->progress();
113 progressBar->setProgress( ++p );
114 kapp->processEvents();
115 str = ( path + "/MSSONY/PJ" );
116 TDEIO::NetAccess::mkdir( str,( TQWidget* )0L );
117
118
119 p = progressBar->progress();
120 progressBar->setProgress( ++p );
121 kapp->processEvents();
122
123 // create the title slides
124 TQPixmap titleSlide( 1024, 768 );
125 titleSlide.fill( backColour );
126 TQPainter painter( &titleSlide );
127
128 //the second title is just blank, so create that now
129 KTempFile tmp;
130 TQString filename = path + slidePath + "/SPJT0002.JPG";
131 titleSlide.save( tmp.name(), "JPEG" );
132 TDEIO::NetAccess::file_move( tmp.name(), filename, -1, true /*overwrite*/);
133
134 p = progressBar->progress();
135 progressBar->setProgress( ++p );
136 kapp->processEvents();
137
138 // and put the specified title string on the first slide
139 TQFont textFont( "SansSerif", 96 );
140 painter.setFont( textFont );
141 painter.setPen( textColour );
142 painter.drawText( titleSlide.rect(), TQt::AlignCenter | TQt::WordBreak, title );
143 filename = path + slidePath + "/SPJT0001.JPG";
144
145 KTempFile tmp2;
146 titleSlide.save( tmp2.name(), "JPEG" );
147 TDEIO::NetAccess::file_move( tmp2.name(), filename, -1, true /*overwrite*/);
148
149 p = progressBar->progress();
150 progressBar->setProgress( ++p );
151 kapp->processEvents();
152
153}
154
155void KPrMSPresentation::createSlidesPictures( KProgress *progressBar )
156{
157 if ( slideInfos.isEmpty() )
158 return;
159 TQString filename;
160 int p;
161 for ( unsigned int i = 0; i < slideInfos.count(); i++ ) {
162 int pgNum = slideInfos[i].pageNumber;
163 filename.sprintf("/SPJP%04i.JPG", i+3);
164
165 KTempFile tmp;
166
167 view->getCanvas()->exportPage( pgNum, 1023, 767,
168 tmp.name(), "JPEG" );
169
170 TDEIO::NetAccess::file_move( tmp.name(), ( path + slidePath + filename ), -1, true /*overwrite*/);
171
172 p = progressBar->progress();
173 progressBar->setProgress( ++p );
174 kapp->processEvents();
175 }
176}
177
178void KPrMSPresentation::createIndexFile( KProgress *progressBar )
179{
180 int p;
181 KTempFile sppFile;
182
183 TQString filenameStore = (path + "/MSSONY/PJ/" + title + ".SPP");
184
185 TQDataStream sppStream( sppFile.file() );
186 sppStream.setByteOrder(TQDataStream::LittleEndian);
187 p = progressBar->progress();
188 progressBar->setProgress( ++p );
189 kapp->processEvents();
190
191 // We are doing little endian
192 sppStream << (TQ_UINT32)0x00505053; // SPP magic header
193 sppStream << (TQ_UINT32)0x00000000; // four null bytes
194 sppStream << (TQ_UINT32)0x30303130; // version(?) 0100
195 sppStream << (TQ_UINT32)0x00000000; // more nulls
196 sppStream << (TQ_UINT32)(slideInfos.count());
197
198 // DCIM path 1, 68 bytes null padded
199 char buff[68];
200 strncpy( buff, TQString("%1").arg(slidePath).ascii(), 67 );
201 buff[67] = 0x00;
202 sppStream.writeRawBytes( buff, 68 );
203 sppStream << (TQ_UINT32)0x00000001; // fixed value
204 sppStream << (TQ_UINT32)0x00000005; // fixed value
205 sppStream << (TQ_UINT32)0x00000000; // more nulls
206 sppStream << (TQ_UINT32)0x00000000; // more nulls
207 sppStream << (TQ_UINT32)0x00000000; // more nulls
208 sppStream << (TQ_UINT32)0x00000000; // more nulls
209 sppStream << (TQ_UINT32)0x00000000; // more nulls
210 sppStream << (TQ_UINT32)0x00000000; // more nulls
211 p = progressBar->progress();
212 progressBar->setProgress( ++p );
213 kapp->processEvents();
214
215 // title 1, 16 bytes null padded
216 strncpy( buff, "SPJT0001.JPG", 15 );
217 buff[15] = 0x00;
218 sppStream.writeRawBytes( buff, 16 );
219
220 // title 2, 16 bytes null padded
221 strncpy( buff, "SPJT0002.JPG", 15 );
222 buff[15] = 0x00;
223 sppStream.writeRawBytes( buff, 16 );
224
225
226 // type face (?), 44 bytes null padded
227 strncpy( buff, "MS Sans Serif", 43 );
228 buff[44] = 0x00;
229 sppStream.writeRawBytes( buff, 44 );
230
231 //not really sure what this is about
232 sppStream << (TQ_UINT32)0xffff0000;
233 sppStream << (TQ_UINT32)0xffff00ff;
234 sppStream << (TQ_UINT32)0xffff00ff;
235 sppStream << (TQ_UINT32)0x000000ff;
236 sppStream << (TQ_UINT32)0x00000002;
237 for (int i = 0; i < (296/4); i++) {
238 sppStream << (TQ_UINT32)0x00000000;
239 }
240 p = progressBar->progress();
241 progressBar->setProgress( ++p );
242 kapp->processEvents();
243
244 // Add in the slide filenames
245 TQString filename;
246 for ( unsigned int i = 0; i < slideInfos.count(); i++ ) {
247 filename.sprintf("SPJP%04i.JPG", i+3);
248 strncpy( buff, filename.ascii(), 63 );
249 buff[64] = 0x00;
250 sppStream.writeRawBytes( buff, 64 );
251 p = progressBar->progress();
252 progressBar->setProgress( ++p );
253 kapp->processEvents();
254 }
255
256 // OK, now we need to fill to 16384 bytes
257 // the logic is 16384 bytes total, lead in is 512 bytes, and there
258 // is 64 bytes for each real slide
259 for(unsigned int i = 0; i < (16384-512-64*(slideInfos.count()))/4; i++) {
260 sppStream << (TQ_UINT32)0x00000000;
261 }
262
263 p = progressBar->progress();
264 progressBar->setProgress( ++p );
265 kapp->processEvents();
266
267 sppFile.close();
268 TDEIO::NetAccess::file_move( sppFile.name(), filenameStore, -1, true /*overwrite*/);
269}
270
271void KPrMSPresentation::init()
272{
273 title = i18n("Slideshow");
274
275 for ( unsigned int i = 0; i < doc->getPageNums(); i++ )
276 {
277 if ( doc->isSlideSelected( i ) )
278 {
279 SlideInfo info;
280 info.pageNumber = i;
281 slideInfos.append( info );
282 }
283 }
284 if ( slideInfos.isEmpty() )
285 kdWarning() << "No slides selected!" << endl;
286 backColour = TQt::black;
287 textColour = TQt::white;
288
289 path = TDEGlobalSettings::documentPath();
290}
291
292KPrMSPresentationSetup::KPrMSPresentationSetup( KPrDocument *_doc, KPrView *_view )
293 : TQDialog( 0, "", false ), msPres( _doc, _view )
294{
295 doc = _doc;
296 view = _view;
297
298
299 TQLabel *helptext = new TQLabel( this );
300 helptext->setAlignment( TQt::WordBreak | TQt::AlignTop| TQt::AlignLeft );
301 helptext->setText( i18n( "Please enter the directory where the memory stick "
302 "presentation should be saved. Please also enter a "
303 "title for the slideshow presentation. " ) );
304
305 TQLabel *lable2 = new TQLabel( i18n("Path:"), this );
306 lable2->setAlignment( TQt::AlignVCenter | TQt::AlignRight );
307 path=new KURLRequester( this );
308 path->setMode( KFile::Directory);
309 path->lineEdit()->setText(msPres.getPath());
310 lable2->setBuddy(path);
311 TQHBoxLayout *pathLayout = new TQHBoxLayout;
312 pathLayout->addWidget(lable2);
313 pathLayout->addWidget(path);
314
315 connect( path, TQ_SIGNAL( textChanged(const TQString&) ),
316 this, TQ_SLOT( slotChoosePath(const TQString&) ) );
317 connect( path, TQ_SIGNAL( urlSelected( const TQString&) ),
318 this, TQ_SLOT( slotChoosePath(const TQString&) ) );
319
320
321 TQLabel *lable1 = new TQLabel( i18n("Title:"), this, "lable1" );
322 lable1->setAlignment( TQt::AlignVCenter | TQt::AlignRight );
323 // TODO - check if there is already a presentation with this title, and
324 // add a number after it until there isn't.
325 title = new KLineEdit( msPres.getTitle(), this );
326 lable1->setBuddy( title );
327 TQHBoxLayout *titleLayout = new TQHBoxLayout;
328 titleLayout->addWidget( lable1 );
329 titleLayout->addWidget( title );
330
331 TQHBox *moreBox = new TQHBox( this );
332 TQPushButton *showColourButton = new TQPushButton( i18n("&Set Colors"), moreBox );
333 showColourButton->setToggleButton( true );
334 connect( showColourButton, TQ_SIGNAL( toggled(bool) ), this, TQ_SLOT( showColourGroup(bool) ) );
335
336 TQVBoxLayout *topLayout = new TQVBoxLayout;
337 topLayout->addWidget( helptext );
338 topLayout->addSpacing( 10 );
339 topLayout->addLayout( pathLayout );
340 topLayout->addLayout( titleLayout );
341 topLayout->addWidget( moreBox );
342
343 colourGroup = new TQGroupBox( 2, TQt::Vertical,
344 i18n("Preliminary Slides"),
345 this , "colourBox" );
346 TQWhatsThis::add( colourGroup,
347 i18n( "This section allows you to set the colors for "
348 "the preliminary slides; it does not affect the "
349 "presentation in any way, and it is normal to "
350 "leave these set to the default.") );
351 TQHBox *textColourLayout = new TQHBox( colourGroup );
352 TQLabel *lable3 = new TQLabel( i18n("Text color:"), textColourLayout );
353 lable3->setAlignment( TQt::AlignVCenter | TQt::AlignRight );
354 textColour = new KColorButton( msPres.getTextColour(), textColourLayout );
355 lable3->setBuddy( textColour );
356
357 TQHBox *backgroundColourLayout = new TQHBox( colourGroup );
358 TQLabel *lable4 = new TQLabel( i18n("Background color:"), backgroundColourLayout );
359 lable4->setAlignment( TQt::AlignVCenter | TQt::AlignRight );
360 backColour = new KColorButton( msPres.getBackColour(), backgroundColourLayout );
361 lable4->setBuddy( backColour );
362 colourGroup->setHidden( true );
363
364 TQHBox *buttonLayout = new TQHBox( this );
365 KPushButton *helpButton = new KPushButton( KStdGuiItem::help(), buttonLayout );
366 TQWhatsThis::add( helpButton,
367 i18n( "Selecting this button will take you to the KPresenter "
368 "documentation that provides more information on how "
369 "to use the Memory Stick export function. ") );
370 KPushButton *createButton = new KPushButton( KStdGuiItem::ok(), buttonLayout );
371 TQWhatsThis::add( createButton,
372 i18n( "Selecting this button will proceed to generating "
373 "the presentation in the special Sony format." ) );
374 KPushButton *cancelButton = new KPushButton( KStdGuiItem::cancel(), buttonLayout );
375 TQWhatsThis::add( cancelButton,
376 i18n( "Selecting this button will cancel out of the "
377 "generation of the presentation, and return "
378 "to the normal KPresenter view. No files will "
379 "be affected." ) );
380
381 mainLayout = new TQVBoxLayout( this );
382 mainLayout->setMargin(11);
383 mainLayout->setSpacing(6);
384 mainLayout->addLayout(topLayout);
385 mainLayout->addSpacing( 10 );
386 mainLayout->addWidget(colourGroup);
387 mainLayout->addWidget(buttonLayout);
388 mainLayout->setResizeMode( TQLayout::Fixed );
389 mainLayout->setGeometry( TQRect( 0, 0, 300, 220 ) );
390
391 connect( helpButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT ( helpMe() ) );
392 connect( cancelButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( reject() ) );
393 connect( createButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( finish() ) );
394}
395
396KPrMSPresentationSetup::~KPrMSPresentationSetup()
397{
398 view->enableMSPres();
399}
400
401void KPrMSPresentationSetup::createMSPresentation( KPrDocument *_doc, KPrView *_view )
402{
403 KPrMSPresentationSetup *dlg = new KPrMSPresentationSetup( _doc, _view );
404
405 dlg->setCaption( i18n( "Create Memory Stick Slideshow" ) );
406 dlg->exec();
407 delete dlg;
408}
409
410void KPrMSPresentationSetup::showColourGroup(bool on)
411{
412 if (on) {
413 colourGroup->setHidden( false );
414 mainLayout->setGeometry( TQRect(0, 0, 300, 220 ) );
415 } else {
416 colourGroup->setHidden( true );
417 mainLayout->setGeometry( TQRect(0, 0, 300, 320 ) );
418 }
419}
420
421void KPrMSPresentationSetup::helpMe()
422{
423 kapp->invokeHelp("ms-export");
424}
425
426void KPrMSPresentationSetup::finish()
427{
428 msPres.setTitle( title->text() );
429
430 msPres.setBackColour( backColour->color() );
431 msPres.setTextColour( textColour->color() );
432 msPres.setPath( path->lineEdit()->text() );
433
434 // Things to sanity check:
435 // 1. that the directory exists. If not, offer to create it.
436 // 2. that the directory is writable.
437 // 3. that the .spp file doesn't already exist. If it does, offer to overwrite it.
438 // If we fail to create a directory, or the user tells us not to bother creating it,
439 // or the user doesn't want to overwrite it, go back.
440 TQString pathname = path->lineEdit()->text();
441
442 // path doesn't exist. ask user if it should be created.
443 if ( !TDEIO::NetAccess::exists(pathname, false, this) ) {
444 TQString msg = i18n( "<qt>The directory <b>%1</b> does not exist.<br>"
445 "Do you want create it?</qt>" );
446 if( KMessageBox::questionYesNo( this, msg.arg( pathname ),
447 i18n( "Directory Not Found" ) )
448 == KMessageBox::Yes)
449 {
450 // we are trying to create the directory
451 TQDir dir;
452 bool ok = TDEIO::NetAccess::mkdir( pathname,this );
453 if( !ok ) {
454 // then directory couldn't be created
455 KMessageBox::sorry( this,
456 i18n( "Cannot create directory." ) );
457 path->setFocus();
458 return;
459 }
460 }
461 else {
462 // user preferred not to create directory
463 path->setFocus();
464 return;
465 }
466 }
467
468 TQString sppFile( pathname + "/MSSONY/PJ/" + title->text() + ".SPP" );
469 if (TDEIO::NetAccess::exists(sppFile, false, this ) ) {
470 if ( KMessageBox::warningYesNo( 0,
471 i18n( "You are about to overwrite an existing index "
472 "file : %1.\n "
473 "Do you want to proceed?" ).arg( sppFile ),
474 i18n( "Overwrite Presentation" ) )
475 == KMessageBox::No) {
476 path->setFocus();
477 return;
478 }
479 }
480
481 close();
482
483 KPrMSPresentationCreateDialog::createMSPresentation( doc, view, msPres );
484
485}
486
487void KPrMSPresentationSetup::slotChoosePath(const TQString &text)
488{
489 msPres.setPath(text);
490}
491
492
493
494
495KPrMSPresentationCreateDialog::KPrMSPresentationCreateDialog( KPrDocument *_doc, KPrView *_view,
496 const KPrMSPresentation &_msPres )
497 : TQDialog( 0, "", false ), msPres( _msPres )
498{
499 doc = _doc;
500 view = _view;
501
502 setupGUI();
503}
504
505KPrMSPresentationCreateDialog::~KPrMSPresentationCreateDialog()
506{
507 view->enableMSPres();
508}
509
510void KPrMSPresentationCreateDialog::createMSPresentation( KPrDocument *_doc, KPrView *_view,
511 const KPrMSPresentation &_msPres )
512{
513 KPrMSPresentationCreateDialog *dlg = new KPrMSPresentationCreateDialog( _doc, _view, _msPres );
514
515 dlg->setCaption( i18n( "Create Memory Stick Slideshow" ) );
516 dlg->resize( 400, 250 );
517 dlg->show();
518 dlg->start();
519}
520
521void KPrMSPresentationCreateDialog::start()
522{
523 setCursor( waitCursor );
524 initCreation();
525 createSlidesPictures();
526 createIndexFile();
527 setCursor( arrowCursor );
528
529 bDone->setEnabled( true );
530}
531
532void KPrMSPresentationCreateDialog::initCreation()
533{
534 TQFont f = step1->font(), f2 = step1->font();
535 f.setBold( true );
536 step1->setFont( f );
537
538 progressBar->setProgress( 0 );
539 progressBar->setTotalSteps( msPres.initSteps() );
540
541 msPres.initCreation( progressBar );
542
543 step1->setFont( f2 );
544 progressBar->setProgress( progressBar->totalSteps() );
545}
546
547void KPrMSPresentationCreateDialog::createSlidesPictures()
548{
549 TQFont f = step2->font(), f2 = f;
550 f.setBold( true );
551 step2->setFont( f );
552
553 progressBar->setProgress( 0 );
554 if ( msPres.slidesSteps() > 0 )
555 {
556 progressBar->setTotalSteps( msPres.slidesSteps() );
557 msPres.createSlidesPictures( progressBar );
558 }
559
560 step2->setFont( f2 );
561 progressBar->setProgress( progressBar->totalSteps() );
562}
563
564void KPrMSPresentationCreateDialog::createIndexFile()
565{
566 TQFont f = step3->font(), f2 = f;
567 f.setBold( true );
568 step3->setFont( f );
569
570 progressBar->setProgress( 0 );
571 if ( msPres.indexFileSteps() > 0 )
572 {
573 progressBar->setTotalSteps( msPres.indexFileSteps() );
574 msPres.createIndexFile( progressBar );
575 }
576
577 step3->setFont( f2 );
578 progressBar->setProgress( progressBar->totalSteps() );
579}
580
581void KPrMSPresentationCreateDialog::setupGUI()
582{
583 back = new TQVBox( this );
584 back->setMargin( KDialog::marginHint() );
585
586 TQFrame *line;
587
588 step1 = new TQLabel( i18n( "Create directory structure" ), back );
589 step2 = new TQLabel( i18n( "Create pictures of the slides" ), back );
590 step3 = new TQLabel( i18n( "Create index file" ), back );
591
592 line = new TQFrame( back );
593 line->setFrameStyle( TQFrame::HLine | TQFrame::Sunken );
594 line->setMaximumHeight( 20 );
595
596 progressBar = new KProgress( back );
597
598 line = new TQFrame( back );
599 line->setFrameStyle( TQFrame::HLine | TQFrame::Sunken );
600 line->setMaximumHeight( 20 );
601
602 KButtonBox *bb = new KButtonBox( back );
603 bb->addStretch();
604 bDone = bb->addButton( i18n( "Done" ) );
605
606 bDone->setEnabled( false );
607
608 connect( bDone, TQ_SIGNAL( clicked() ), this, TQ_SLOT( accept() ) );
609}
610
611void KPrMSPresentationCreateDialog::resizeEvent( TQResizeEvent *e )
612{
613 TQDialog::resizeEvent( e );
614 back->resize( size() );
615}
616
617#include "KPrGradient.h"
618#include "KPrMSPresentationSetup.moc"