~ubuntu-branches/ubuntu/quantal/qgis/quantal

« back to all changes in this revision

Viewing changes to src/composer/qgscomposer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): William Grant
  • Date: 2007-05-06 13:42:32 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070506134232-pyli6t388w5asd8x
Tags: 0.8.0-3ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
  - debian/rules, debian/qgis.install, debian/qgis.dirs debian/qgis.desktop:
    Add and install .desktop.
* debian/qgis.desktop: Remove Applications category; it's not real.
* Modify Maintainer value to match Debian-Maintainer-Field Spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                         qgscomposer.cpp  -  description
 
3
                             -------------------
 
4
    begin                : January 2005
 
5
    copyright            : (C) 2005 by Radim Blazek
 
6
    email                : blazek@itc.it
 
7
 ***************************************************************************/
 
8
 
 
9
/***************************************************************************
 
10
 *                                                                         *
 
11
 *   This program is free software; you can redistribute it and/or modify  *
 
12
 *   it under the terms of the GNU General Public License as published by  *
 
13
 *   the Free Software Foundation; either version 2 of the License, or     *
 
14
 *   (at your option) any later version.                                   *
 
15
 *                                                                         *
 
16
 ***************************************************************************/
 
17
#include "qgscomposer.h"
 
18
 
 
19
#include "qgisapp.h"
 
20
#include "qgsapplication.h"
 
21
#include "qgscomposerview.h"
 
22
#include "qgscomposition.h"
 
23
#include "qgsexception.h"
 
24
#include "qgsproject.h"
 
25
#include "qgsmessageviewer.h"
 
26
#include "qgscontexthelp.h"
 
27
 
 
28
#include <QDesktopWidget>
 
29
#include <QFileDialog>
 
30
#include <QFileInfo>
 
31
#include <QMatrix>
 
32
#include <QMessageBox>
 
33
#include <QPainter>
 
34
#include <Q3Picture>
 
35
#include <QPrinter>
 
36
#include <QPrintDialog>
 
37
#include <QSettings>
 
38
#include <QIcon>
 
39
#include <QPixmap>
 
40
#include <QToolBar>
 
41
#include <QImageWriter>
 
42
#include <QCheckBox>
 
43
#include <QSizeGrip>
 
44
#include <iostream>
 
45
 
 
46
 
 
47
QgsComposer::QgsComposer( QgisApp *qgis): QMainWindow()
 
48
{
 
49
  setupUi(this);
 
50
  setupTheme();
 
51
  setWindowTitle(tr("QGIS - print composer"));
 
52
 
 
53
  // Template save and load is not yet implemented, so disable those actions
 
54
  mActionOpenTemplate->setEnabled(false);
 
55
  mActionSaveTemplateAs->setEnabled(false);
 
56
 
 
57
  mQgis = qgis;
 
58
  mFirstTime = true;
 
59
 
 
60
#ifdef QGISDEBUG
 
61
  std::cout << "QgsComposer::QgsComposer" << std::endl;
 
62
#endif
 
63
 
 
64
  mView = new QgsComposerView ( this, mViewFrame);
 
65
  mPrinter = 0;
 
66
 
 
67
  QGridLayout *l = new QGridLayout(mViewFrame, 1, 1 );
 
68
  l->addWidget( mView, 0, 0 );
 
69
 
 
70
  mCompositionOptionsLayout = new QGridLayout( mCompositionOptionsFrame, 1, 1 );
 
71
  mItemOptionsLayout = new QGridLayout( mItemOptionsFrame, 1, 1 );
 
72
 
 
73
  mCompositionNameComboBox->insertItem( tr("Map 1") );
 
74
 
 
75
  mComposition  = new QgsComposition( this, 1 );
 
76
  mComposition->setActive ( true );
 
77
 
 
78
  // Create size grip (needed by Mac OS X for QMainWindow if QStatusBar is not visible)
 
79
  mSizeGrip = new QSizeGrip(this);
 
80
  mSizeGrip->resize(mSizeGrip->sizeHint());
 
81
  mSizeGrip->move(rect().bottomRight() - mSizeGrip->rect().bottomRight());
 
82
 
 
83
  if ( ! connect( mQgis, SIGNAL( projectRead() ), this, SLOT( projectRead()) ) ) {
 
84
    qDebug( "unable to connect to projectRead" );
 
85
  } 
 
86
  if ( ! connect( mQgis, SIGNAL( newProject() ), this, SLOT(newProject()) ) ) {
 
87
    qDebug( "unable to connect to newProject" );
 
88
  }
 
89
 
 
90
  if ( ! connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(saveWindowState()) ) ) { 
 
91
    qDebug( "unable to connect to aboutToQuit" );
 
92
  }
 
93
  restoreWindowState();
 
94
 
 
95
  selectItem(); // Set selection tool
 
96
}
 
97
 
 
98
QgsComposer::~QgsComposer()
 
99
{
 
100
}
 
101
 
 
102
void QgsComposer::setupTheme()
 
103
{
 
104
  //calculate the active theme path
 
105
  QString myThemePath= QgsApplication::themePath();
 
106
  
 
107
 
 
108
  //now set all the icons
 
109
  mActionOpenTemplate->setIconSet(QIcon(QPixmap(myThemePath + "/mActionFileOpen.png")));
 
110
  mActionSaveTemplateAs->setIconSet(QIcon(QPixmap(myThemePath + "/mActionFileSaveAs.png")));
 
111
  mActionExportAsImage->setIconSet(QIcon(QPixmap(myThemePath + "/mActionExportMapServer.png")));
 
112
  mActionExportAsSVG->setIconSet(QIcon(QPixmap(myThemePath + "/mActionSaveAsSVG.png")));
 
113
  mActionPrint->setIconSet(QIcon(QPixmap(myThemePath + "/mActionFilePrint.png")));
 
114
  mActionZoomAll->setIconSet(QIcon(QPixmap(myThemePath + "/mActionZoomFullExtent.png")));
 
115
  mActionZoomIn->setIconSet(QIcon(QPixmap(myThemePath + "/mActionZoomIn.png")));
 
116
  mActionZoomOut->setIconSet(QIcon(QPixmap(myThemePath + "/mActionZoomOut.png")));
 
117
  mActionRefreshView->setIconSet(QIcon(QPixmap(myThemePath + "/mActionDraw.png")));
 
118
  mActionAddImage->setIconSet(QIcon(QPixmap(myThemePath + "/mActionSaveMapAsImage.png")));
 
119
  mActionAddNewMap->setIconSet(QIcon(QPixmap(myThemePath + "/mActionAddRasterLayer.png")));
 
120
  mActionAddNewLabel->setIconSet(QIcon(QPixmap(myThemePath + "/mActionLabel.png")));
 
121
  mActionAddNewVectLegend->setIconSet(QIcon(QPixmap(myThemePath + "/mActionAddLegend.png")));
 
122
  mActionAddNewScalebar->setIconSet(QIcon(QPixmap(myThemePath + "/mActionScaleBar.png")));
 
123
  mActionSelectMoveItem->setIconSet(QIcon(QPixmap(myThemePath + "/mActionPan.png")));
 
124
}
 
125
 
 
126
void QgsComposer::open ( void )
 
127
{
 
128
  if ( mFirstTime ) {
 
129
    mComposition->createDefault();
 
130
    mFirstTime = false;
 
131
  }
 
132
 
 
133
  show();
 
134
}
 
135
 
 
136
void QgsComposer::removeWidgetChildren ( QWidget *w )
 
137
{
 
138
#ifdef QGISDEBUG
 
139
  std::cout << "QgsComposer::removeWidgetChildren" << std::endl;
 
140
#endif
 
141
 
 
142
  const QObjectList ol = mItemOptionsFrame->children();
 
143
  if ( !ol.isEmpty() ) 
 
144
  {
 
145
    QListIterator<QObject*> olit( ol );
 
146
    QObject *ob;
 
147
    while( olit.hasNext() )
 
148
    {
 
149
      ob = olit.next();
 
150
      if( ob->isWidgetType() ) 
 
151
      {
 
152
        QWidget *ow = (QWidget *) ob;
 
153
 
 
154
        // The following line is legacy Qt3, is not supported in Qt4
 
155
        // and can cause a SIGABRT
 
156
        //w->removeChild ( ob );
 
157
        // instead:
 
158
        ow->setParent(0);
 
159
        // TODO: Eventually mItemOptionsFrame should be made
 
160
        // a Qt4 QStackedWidget and all this removeWidgetChildren
 
161
        // shenanigans can alledgedly go away
 
162
 
 
163
        ow->hide();
 
164
      }
 
165
    }
 
166
  }
 
167
}
 
168
 
 
169
void QgsComposer::showCompositionOptions ( QWidget *w ) {
 
170
#ifdef QGISDEBUG
 
171
  std::cout << "QgsComposer::showCompositionOptions" << std::endl;
 
172
#endif
 
173
  removeWidgetChildren ( mCompositionOptionsFrame );
 
174
 
 
175
  if ( w ) { 
 
176
    w->reparent ( mCompositionOptionsFrame, QPoint(0,0), TRUE );
 
177
    mCompositionOptionsLayout->addWidget( w, 0, 0 );
 
178
  }
 
179
}
 
180
 
 
181
void QgsComposer::showItemOptions ( QWidget *w )
 
182
{
 
183
#ifdef QGISDEBUG
 
184
  std::cout << "QgsComposer::showItemOptions" << std::endl;
 
185
#endif
 
186
  removeWidgetChildren ( mItemOptionsFrame );
 
187
 
 
188
  // NOTE: It is better to leave there the tab with item options if w is NULL
 
189
 
 
190
  if ( w ) {
 
191
    w->reparent ( mItemOptionsFrame, QPoint(0,0), TRUE );
 
192
 
 
193
    mItemOptionsLayout->addWidget( w, 0, 0 );
 
194
    mOptionsTabWidget->setCurrentPage (1);
 
195
  }
 
196
}
 
197
 
 
198
QgsMapCanvas *QgsComposer::mapCanvas(void)
 
199
{
 
200
  return mQgis->getMapCanvas();
 
201
}
 
202
 
 
203
QgsComposerView *QgsComposer::view(void)
 
204
{
 
205
  return mView;
 
206
}
 
207
 
 
208
QgsComposition *QgsComposer::composition(void)
 
209
{
 
210
  return mComposition;
 
211
}
 
212
 
 
213
void QgsComposer::zoomFull(void)
 
214
{
 
215
  QMatrix m;
 
216
 
 
217
  // scale
 
218
  double xscale = 1.0 * (mView->width()-10) / mComposition->canvas()->width();
 
219
  double yscale = 1.0 * (mView->height()-10) / mComposition->canvas()->height();
 
220
  double scale = ( xscale < yscale ? xscale : yscale );
 
221
 
 
222
  // translate
 
223
  double dx = ( mView->width() - scale * mComposition->canvas()->width() ) / 2;
 
224
  double dy = ( mView->height() - scale * mComposition->canvas()->height() ) / 2;
 
225
 
 
226
  m.translate ( dx, dy );
 
227
  m.scale( scale, scale );
 
228
 
 
229
  mView->setWorldMatrix( m );
 
230
  mView->repaintContents();
 
231
}
 
232
 
 
233
void QgsComposer::on_mActionZoomAll_activated(void)
 
234
{
 
235
  zoomFull();
 
236
}
 
237
 
 
238
QMatrix QgsComposer::updateMatrix(double scaleChange)
 
239
{
 
240
  double scale = mView->worldMatrix().m11() * scaleChange; // get new scale
 
241
 
 
242
  double dx = ( mView->width() - scale * mComposition->canvas()->width() ) / 2;
 
243
  double dy = ( mView->height() - scale * mComposition->canvas()->height() ) / 2;
 
244
  
 
245
  // don't translate if composition is bigger than view
 
246
  if (dx < 0) dx = 0;
 
247
  if (dy < 0) dy = 0;
 
248
  
 
249
  // create new world matrix:  
 
250
  QMatrix m;
 
251
  m.translate ( dx, dy );
 
252
  m.scale ( scale, scale );
 
253
  return m;
 
254
}
 
255
 
 
256
void QgsComposer::on_mActionZoomIn_activated(void)
 
257
{
 
258
  QMatrix m = updateMatrix(2);
 
259
  mView->setWorldMatrix( m );
 
260
  mView->repaintContents();
 
261
}
 
262
 
 
263
void QgsComposer::on_mActionZoomOut_activated(void)
 
264
{
 
265
  QMatrix m = updateMatrix(0.5);
 
266
  mView->setWorldMatrix( m );
 
267
  mView->repaintContents();
 
268
}
 
269
 
 
270
void QgsComposer::on_mActionRefreshView_activated(void)
 
271
{
 
272
  mComposition->refresh();
 
273
  mView->repaintContents();
 
274
}
 
275
 
 
276
void QgsComposer::on_mActionPrint_activated(void)
 
277
{
 
278
  /* Uff!!! It is impossible to set a custom page size for QPrinter.
 
279
   * Only the sizes hardcoded in Qt library can be used.
 
280
   * 'Fortunately', it seems that everything is written to postscript output file,
 
281
   * regardless the pages size ->
 
282
   *
 
283
   * 1) outputToFile == false: If the output page size doesn't match the user defined size 
 
284
   *                           (in QgsComposer) the output is rescaled and centered so that 
 
285
   *                           it fit to the select output page size. 
 
286
   *                           a warning is displayed, that the map was rescaled.
 
287
   *                           
 
288
   * 2) outputToFile == true:  the output postscript file is written (page size is not
 
289
   *                           important but bigger is better because it lefts enough space
 
290
   *                           in BoundingBox definition), then the file is reopened, 
 
291
   *                           and the BoundingBox is redefined.
 
292
   */ 
 
293
 
 
294
  // NOTE: QT 3.2 has QPrinter::setOptionEnabled but only for three options 
 
295
  if ( !mPrinter ) {
 
296
 
 
297
    mPrinter = new QPrinter ( QPrinter::PrinterResolution );
 
298
    //mPrinter = new QPrinter ( QPrinter::HighResolution );
 
299
    //mPrinter = new QPrinter ( QPrinter::ScreenResolution );
 
300
    mPrinter->setFullPage ( true );
 
301
#ifndef Q_OS_MACX
 
302
    // For Qt/Mac 3, don't set outputToFile to true before calling setup 
 
303
    // because it wiil suppress the Print dialog and output to file without
 
304
    // giving the user a chance to select a printer instead.
 
305
    // The Mac Print dialog provides an option to create a pdf which is
 
306
    // intended to be invisible to the application. If an eps is desired,
 
307
    // a custom Mac Print dialog is needed.
 
308
    
 
309
    // There is a bug in Qt<=4.2.2 (dialog is not correct) if output is set to file
 
310
    // => disable until they fix it
 
311
    //mPrinter->setOutputToFile (true ) ;
 
312
    //mPrinter->setOutputFileName ( QDir::convertSeparators ( QDir::home().path() + "/" + "qgis.eps") );
 
313
#endif
 
314
 
 
315
    if ( mComposition->paperOrientation() == QgsComposition::Portrait ) {
 
316
      mPrinter->setOrientation ( QPrinter::Portrait );
 
317
    } else {
 
318
      mPrinter->setOrientation ( QPrinter::Landscape );
 
319
    }
 
320
    mPrinter->setColorMode ( QPrinter::Color );
 
321
    mPrinter->setPageSize ( QPrinter::A4 );
 
322
  }
 
323
  else
 
324
  {
 
325
      // Because of bug in Qt<=4.2.2 (dialog is not correct) we have to reset always
 
326
      // to printer otherwise print to file is checked but printer combobox is in dialog
 
327
      mPrinter->setOutputToFile (false) ;
 
328
  }
 
329
 
 
330
  mPrinter->setResolution ( mComposition->resolution() );
 
331
 
 
332
  //if ( mPrinter->setup(this) ) {
 
333
  QPrintDialog printDialog ( mPrinter, this);
 
334
  if ( printDialog.exec() == QDialog::Accepted ) 
 
335
  {
 
336
    // TODO: mPrinter->setup() moves the composer under Qgisapp, get it to foreground somehow
 
337
    //       raise() for now, is it something better?
 
338
    raise ();
 
339
 
 
340
    // TODO: Qt does not add pagesize to output file, it can cause problems if ps2pdf is used 
 
341
    // or if default page on printer is different.
 
342
    // We should add somewhere in output file:
 
343
    // << /PageSize [ %d %d ] >> setpagedevice
 
344
    // %d %d is width and height in points
 
345
    
 
346
    // WARNING: If QCanvasView recieves repaint signal during the printing
 
347
    // (e.g. covered by QPrinter::setup dialog) it breaks somehow drawing of QCanvas items 
 
348
    // (for example not all features in the map are drawn.
 
349
    // I don't know how to stop temporarily updating, (I don't want to reimplement 
 
350
    // repaint in QCanvasView, so I unset the view, print and reset.
 
351
    mView->setCanvas(0);
 
352
 
 
353
    int resolution = mPrinter->resolution();
 
354
 
 
355
    std::cout << "Resolution = " << resolution << std::endl;
 
356
 
 
357
    double scale = resolution / 25.4 / mComposition->scale();
 
358
 
 
359
    mComposition->setPlotStyle ( QgsComposition::Postscript );
 
360
 
 
361
    if ( !mPrinter->outputFileName().isNull() ) {
 
362
      try {
 
363
      std::cout << "Print to file" << std::endl;
 
364
 
 
365
      QPrinter::PageSize psize;
 
366
      
 
367
      // WARNING mPrinter->outputFormat() returns always 0 in Qt 4.2.2
 
368
      // => we have to check extension
 
369
      bool isPs = false;
 
370
      if ( mPrinter->outputFileName().right(3).toLower() == ".ps"
 
371
           || mPrinter->outputFileName().right(4).toLower() == ".eps" )
 
372
      {
 
373
          isPs = true;
 
374
      }
 
375
      //if ( mPrinter->outputFormat() == QPrinter::PostScriptFormat )
 
376
      if ( isPs )
 
377
      {
 
378
          // NOTE: setPageSize after setup() works, but setOrientation does not
 
379
          //   -> the BoundingBox must follow the orientation 
 
380
 
 
381
          psize = mPrinter->pageSize();
 
382
          // B0 ( 1000x1414mm = 2835x4008pt ) is the biggest defined in Qt, a map can be bigger 
 
383
          // but probably not bigger than 9999x9999pt = 3527x3527mm 
 
384
          mPrinter->setPageSize ( QPrinter::B0 );
 
385
      }
 
386
 
 
387
      QPainter p(mPrinter);
 
388
      p.scale ( scale, scale); 
 
389
 
 
390
      mComposition->canvas()->drawArea ( QRect(0,0, 
 
391
            (int) (mComposition->paperWidth() * mComposition->scale()),
 
392
            (int) (mComposition->paperHeight() * mComposition->scale()) ), 
 
393
            &p, FALSE );
 
394
 
 
395
      p.end();
 
396
 
 
397
      std::cout << "mPrinter->outputFormat() = " << mPrinter->outputFormat() << std::endl;
 
398
      
 
399
      
 
400
      //if ( mPrinter->outputFormat() == QPrinter::PostScriptFormat )
 
401
      if ( isPs )
 
402
      {
 
403
        // reset the page
 
404
        mPrinter->setPageSize ( psize );
 
405
        
 
406
        QFile f(mPrinter->outputFileName());
 
407
        
 
408
        // Overwrite the bounding box
 
409
        std::cout << "Overwrite the bounding box" << std::endl;
 
410
        if (!f.open( QIODevice::ReadWrite )) {
 
411
                throw QgsIOException(tr("Couldn't open " + f.name() + tr(" for read/write")));
 
412
        }
 
413
        Q_LONG offset = 0;
 
414
        Q_LONG size;
 
415
        bool found = false;
 
416
        QString s;
 
417
        char buf[101];
 
418
        while ( !f.atEnd() ) {
 
419
                size = f.readLine ( buf, 100 );
 
420
                s = QString(buf);
 
421
                if ( s.find ("%%BoundingBox:") == 0 ) {
 
422
                found = true;
 
423
                break;
 
424
                }
 
425
                offset += size;
 
426
        }
 
427
        
 
428
        if ( found ) {
 
429
                int w,h;
 
430
        
 
431
                w = (int) ( 72 * mComposition->paperWidth() / 25.4 );
 
432
                h = (int) ( 72 * mComposition->paperHeight() / 25.4 );
 
433
                if ( mPrinter->orientation() == QPrinter::Landscape ) { 
 
434
                int tmp = w; w = h; h = tmp;
 
435
                }
 
436
                s.sprintf( "%%%%BoundingBox: 0 0 %d %d", w, h );
 
437
        
 
438
                if ( s.length() > size ) 
 
439
                {
 
440
                int shift = s.length() - size;
 
441
                shiftFileContent ( &f, offset + size + 1, shift );
 
442
                } else {
 
443
                if ( ! f.at(offset) ) {
 
444
                QMessageBox::warning(this, tr("Error in Print"), tr("Cannot seek"));
 
445
                } else {
 
446
                /* Write spaces (for case the size > s.length() ) */
 
447
                QString es;
 
448
                es.fill(' ', size-1 );
 
449
                f.flush();
 
450
                if ( f.writeBlock ( es.toLocal8Bit().data(), size-1 ) < size-1 ) {
 
451
                QMessageBox::warning(this, tr("Error in Print"), tr("Cannot overwrite BoundingBox"));
 
452
                }
 
453
                f.flush();
 
454
                f.at(offset);
 
455
                f.flush();
 
456
                if ( f.writeBlock ( s.toLocal8Bit().data(), s.length() ) <  s.length()-1 ) {
 
457
                QMessageBox::warning(this, tr("Error in Print"), tr("Cannot overwrite BoundingBox"));
 
458
                }
 
459
                f.flush();
 
460
                }
 
461
                }
 
462
        } else {
 
463
                QMessageBox::warning(this, tr("Error in Print"), tr("Cannot find BoundingBox"));
 
464
        }
 
465
        f.close();
 
466
        
 
467
        // Overwrite translate
 
468
        if ( mPrinter->orientation() == QPrinter::Portrait ) { 
 
469
                std::cout << "Orientation portraint -> overwrite translate" << std::endl;
 
470
                if (!f.open( QIODevice::ReadWrite )) {
 
471
                throw QgsIOException(tr("Couldn't open ") + f.name() + tr(" for read/write"));
 
472
                }
 
473
                offset = 0;
 
474
                found = false;
 
475
        
 
476
                //Example Qt3:
 
477
                //0 4008 translate 1 -1 scale/defM ...
 
478
                //QRegExp rx ( "^0 [^ ]+ translate ([^ ]+ [^ ]+) scale/defM matrix CM d \\} d" );
 
479
                //Example Qt4:
 
480
                //0 0 translate 0.239999 -0.239999 scale } def
 
481
                QRegExp rx ( "^0 [^ ]+ translate ([^ ]+ [^ ]+) scale \\} def" );
 
482
        
 
483
                while ( !f.atEnd() ) {
 
484
                size = f.readLine ( buf, 100 );
 
485
                s = QString(buf);
 
486
                if ( rx.search( s ) != -1 ) {
 
487
                found = true;
 
488
                break;
 
489
                }
 
490
                offset += size;
 
491
                }
 
492
        
 
493
                if ( found ) {
 
494
                int trans;
 
495
        
 
496
                trans = (int) ( 72 * mComposition->paperHeight() / 25.4 );
 
497
                std::cout << "trans = " << trans << std::endl;
 
498
                //Qt3:
 
499
                //s.sprintf( "0 %d translate %s scale/defM matrix CM d } d", trans, (const char *)rx.cap(1).toLocal8Bit().data() );
 
500
                //Qt4:
 
501
                s.sprintf( "0 %d translate %s scale } def\n", trans, (const char *)rx.cap(1).toLocal8Bit().data() );
 
502
        
 
503
                        
 
504
                std::cout << "s.length() = " << s.length() << " size = " << size << std::endl;
 
505
                if ( s.length() > size ) {
 
506
                //QMessageBox::warning(this, tr("Error in Print"), tr("Cannot format translate"));
 
507
                // Move the content up
 
508
                int shift = s.length() - size;
 
509
                /*
 
510
                int last = f.size() + shift -1;
 
511
                for ( int i = last; i > offset + size; i-- )
 
512
                {
 
513
                        f.at(i-shift);
 
514
                        QByteArray ba = f.read(1);
 
515
                        f.at(i);
 
516
                        f.write(ba);
 
517
                }
 
518
                */
 
519
                shiftFileContent ( &f, offset + size + 1, shift );
 
520
                }
 
521
        
 
522
                // Overwrite the row
 
523
                if ( ! f.at(offset) ) {
 
524
                QMessageBox::warning(this, tr("Error in Print"), tr("Cannot seek"));
 
525
                } else {
 
526
                /* Write spaces (for case the size > s.length() ) */
 
527
                QString es;
 
528
                es.fill(' ', size-1 );
 
529
                f.flush();
 
530
                if ( f.writeBlock ( es.toLocal8Bit().data(), size-1 ) < size-1 ) {
 
531
                        QMessageBox::warning(this, tr("Error in Print"), tr("Cannot overwrite translate"));
 
532
                }
 
533
                f.flush();
 
534
                f.at(offset);
 
535
                f.flush();
 
536
                if ( f.writeBlock ( s.toLocal8Bit().data(), s.length() ) <  s.length()-1 ) {
 
537
                        QMessageBox::warning(this, tr("Error in Print"), tr("Cannot overwrite translate"));
 
538
                }
 
539
                f.flush();
 
540
                }
 
541
                } else {
 
542
                QMessageBox::warning(this, tr("Error in Print"), tr("Cannot find translate"));
 
543
                }
 
544
                f.close();
 
545
        }
 
546
      }
 
547
      } catch (QgsIOException e) {
 
548
        QMessageBox::warning(this, tr("File IO Error"), e.what());
 
549
      }
 
550
    } else {  // print to printer
 
551
        bool print = true;
 
552
 
 
553
        // Check size 
 
554
        std::cout << "Paper: " << mPrinter->widthMM() << " x " << mPrinter->heightMM() << std::endl;
 
555
        if ( mComposition->paperWidth() != mPrinter->widthMM() || 
 
556
            mComposition->paperHeight() != mPrinter->heightMM() )
 
557
        {
 
558
          int answer = QMessageBox::warning ( 0, tr("Paper does not match"), 
 
559
              tr("The selected paper size does not match the composition size"),
 
560
              QMessageBox::Ok,  QMessageBox::Abort );
 
561
 
 
562
          if ( answer == QMessageBox::Abort )
 
563
            print = false;
 
564
 
 
565
        }
 
566
 
 
567
        if ( print ) {
 
568
          std::cout << "Printing ... " << std::endl;
 
569
          QPainter p(mPrinter);
 
570
          p.scale ( scale, scale); 
 
571
          mComposition->canvas()->drawArea ( QRect(0,0, 
 
572
                (int) (mComposition->paperWidth() * mComposition->scale()),
 
573
                (int) (mComposition->paperHeight() * mComposition->scale()) ), 
 
574
              &p, FALSE );
 
575
          p.end();
 
576
          std::cout << "... printing finished" << std::endl;
 
577
        }
 
578
      }
 
579
 
 
580
      mComposition->setPlotStyle ( QgsComposition::Preview );
 
581
      mView->setCanvas(mComposition->canvas());
 
582
  } 
 
583
  else 
 
584
  {
 
585
      raise ();
 
586
  }
 
587
}
 
588
 
 
589
bool QgsComposer::shiftFileContent ( QFile *file, Q_LONG start, int shift )
 
590
{
 
591
        int last = file->size() + shift -1;
 
592
        for ( int i = last; i >= start + shift; i-- )
 
593
        {
 
594
            if ( !file->at(i-shift) ) return false;
 
595
            QByteArray ba = file->read(1);
 
596
            if ( ba.isEmpty() ) return false;
 
597
            if ( !file->at(i) ) return false;
 
598
            if ( file->write(ba) != 1 ) return false;
 
599
        }
 
600
        return true;
 
601
}
 
602
 
 
603
void QgsComposer::on_mActionExportAsImage_activated(void)
 
604
{
 
605
  // Image size 
 
606
  int width = (int) (mComposition->resolution() * mComposition->paperWidth() / 25.4); 
 
607
  int height = (int) (mComposition->resolution() * mComposition->paperHeight() / 25.4); 
 
608
 
 
609
  int memuse = width * height * 3 / 1000000;  // pixmap + image
 
610
#ifdef QGISDEBUG
 
611
  std::cout << "Image " << width << " x " << height << std::endl;
 
612
  std::cout << "memuse = " << memuse << std::endl;
 
613
#endif
 
614
 
 
615
  if ( memuse > 200 ) { // cca 4500 x 4500
 
616
    int answer = QMessageBox::warning ( 0, tr("Big image"), 
 
617
        tr("To create image ") + QString::number(width) + " x " 
 
618
        + QString::number(height) 
 
619
        + tr(" requires circa ") 
 
620
        + QString::number(memuse) + tr(" MB of memory"), 
 
621
        QMessageBox::Ok,  QMessageBox::Abort );
 
622
  
 
623
    raise ();
 
624
    if ( answer == QMessageBox::Abort ) return;
 
625
  }
 
626
 
 
627
  // Get file and format (stolen from qgisapp.cpp but modified significantely)
 
628
 
 
629
  //create a map to hold the QImageIO names and the filter names
 
630
  //the QImageIO name must be passed to the mapcanvas saveas image function
 
631
  typedef QMap<QString, QString> FilterMap;
 
632
  FilterMap myFilterMap;
 
633
 
 
634
  //find out the last used filter
 
635
  QSettings myQSettings;  // where we keep last used filter in persistant state
 
636
  QString myLastUsedFormat = myQSettings.readEntry("/UI/lastSaveAsImageFormat", "PNG" );
 
637
  QString myLastUsedFile = myQSettings.readEntry("/UI/lastSaveAsImageFile","qgis.png");
 
638
  QFileInfo file(myLastUsedFile);
 
639
 
 
640
  // get a list of supported output image types
 
641
  int myCounterInt=0;
 
642
  QString myFilters;
 
643
  QString myLastUsedFilter;
 
644
  for ( ; myCounterInt < QImageWriter::supportedImageFormats().count(); myCounterInt++ )
 
645
  {
 
646
    QString myFormat=QString(QImageWriter::supportedImageFormats().at( myCounterInt ));
 
647
    QString myFilter = myFormat + " " + tr("format") + " (*." + myFormat.lower() + " *." + myFormat.upper() + ")";
 
648
    if ( myCounterInt > 0 ) myFilters += ";;";
 
649
    myFilters += myFilter;
 
650
    myFilterMap[myFilter] = myFormat;
 
651
    if ( myFormat == myLastUsedFormat ) 
 
652
    { 
 
653
      myLastUsedFilter = myFilter;
 
654
    }
 
655
  }
 
656
#ifdef QGISDEBUG
 
657
  std::cout << "Available Filters Map: " << std::endl;
 
658
  FilterMap::Iterator myIterator;
 
659
  for ( myIterator = myFilterMap.begin(); myIterator != myFilterMap.end(); ++myIterator )
 
660
  {
 
661
    std::cout << myIterator.key().toLocal8Bit().data() << "  :  " << myIterator.data().toLocal8Bit().data() << std::endl;
 
662
  }
 
663
#endif
 
664
 
 
665
  //create a file dialog using the the filter list generated above
 
666
  std::auto_ptr < QFileDialog > myQFileDialog(
 
667
      new QFileDialog(
 
668
        this,
 
669
        tr("Choose a filename to save the map image as"),
 
670
        file.path(),
 
671
        myFilters
 
672
        )
 
673
      );
 
674
  myQFileDialog->selectFile( file.fileName() );
 
675
 
 
676
  // allow for selection of more than one file
 
677
  myQFileDialog->setMode(QFileDialog::AnyFile);
 
678
 
 
679
  // set the filter to the last one used
 
680
  myQFileDialog->selectFilter(myLastUsedFilter);
 
681
 
 
682
  // set the 'Open' button to something that makes more sense
 
683
  myQFileDialog->setAcceptMode(QFileDialog::AcceptSave);
 
684
 
 
685
  //prompt the user for a filename
 
686
  QString myOutputFileNameQString; // = myQFileDialog->getSaveFileName(); //delete this
 
687
 
 
688
  int result = myQFileDialog->exec();
 
689
  raise ();
 
690
  
 
691
  if ( result != QDialog::Accepted) return;
 
692
 
 
693
  myOutputFileNameQString = myQFileDialog->selectedFile();
 
694
  QString myFilterString = myQFileDialog->selectedFilter();
 
695
#ifdef QGISDEBUG
 
696
  std::cout << "Selected filter: " << myFilterString.toLocal8Bit().data() << std::endl;
 
697
  std::cout << "Image type: " << myFilterMap[myFilterString].toLocal8Bit().data() << std::endl;
 
698
#endif
 
699
 
 
700
  myQSettings.writeEntry("/UI/lastSaveAsImageFormat" , myFilterMap[myFilterString] );
 
701
  myQSettings.writeEntry("/UI/lastSaveAsImageFile", myOutputFileNameQString);
 
702
 
 
703
  if ( myOutputFileNameQString == "" ) return;
 
704
 
 
705
  double scale = (double) (mComposition->resolution() / 25.4 / mComposition->scale());
 
706
 
 
707
  mView->setCanvas(0);
 
708
  mComposition->setPlotStyle ( QgsComposition::Print );
 
709
 
 
710
  QPixmap pixmap ( width, height );
 
711
  pixmap.fill ( QColor(255,255,255) ) ;
 
712
  QPainter p(&pixmap);
 
713
  p.scale ( scale, scale); 
 
714
  mComposition->canvas()->drawArea ( QRect(0,0, 
 
715
        (int) (mComposition->paperWidth() * mComposition->scale()),
 
716
        (int) (mComposition->paperHeight() * mComposition->scale()) ), 
 
717
      &p, FALSE );
 
718
  p.end();
 
719
 
 
720
  mComposition->setPlotStyle ( QgsComposition::Preview );
 
721
  mView->setCanvas(mComposition->canvas());
 
722
 
 
723
  pixmap.save ( myOutputFileNameQString, myFilterMap[myFilterString].toLocal8Bit().data() );
 
724
}
 
725
 
 
726
void QgsComposer::on_mActionExportAsSVG_activated(void)
 
727
{
 
728
  QSettings myQSettings;
 
729
 
 
730
  bool displaySVGWarning = myQSettings.value("/UI/displaySVGWarning", true).toBool();
 
731
 
 
732
  if (displaySVGWarning)
 
733
  {
 
734
    QgsMessageViewer* m = new QgsMessageViewer(this);
 
735
    m->setWindowTitle(tr("SVG warning"));
 
736
    m->setCheckBoxText(tr("Don't show this message again"));
 
737
    m->setCheckBoxState(Qt::Unchecked);
 
738
    m->setCheckBoxVisible(true);
 
739
    m->setMessageAsHtml(tr("<p>The SVG export function in Qgis has several "
 
740
                           "problems due to bugs and deficiencies in the "
 
741
                           "Qt4 svg code. Of note, text does not "
 
742
                           "appear in the SVG file and there are problems "
 
743
                           "with the map bounding box clipping other items "
 
744
                           "such as the legend or scale bar.</p>"
 
745
                           "If you require a vector-based output file from "
 
746
                           "Qgis it is suggested that you try printing "
 
747
                           "to PostScript if the SVG output is not "
 
748
                           "satisfactory."
 
749
                           "</p>"));
 
750
    m->exec();
 
751
 
 
752
    if (m->checkBoxState() == Qt::Checked)
 
753
      myQSettings.setValue("/UI/displaySVGWarning", false);
 
754
    else
 
755
      myQSettings.setValue("/UI/displaySVGWarning", true);
 
756
    delete m;
 
757
  }
 
758
 
 
759
  QString myLastUsedFile = myQSettings.readEntry("/UI/lastSaveAsSvgFile","qgis.svg");
 
760
  QFileInfo file(myLastUsedFile);
 
761
 
 
762
  QFileDialog *myQFileDialog = new QFileDialog( this, tr("Choose a filename to save the map as"),
 
763
                                                file.path(), tr("SVG Format") + " (*.svg *SVG)" );
 
764
  
 
765
  myQFileDialog->selectFile( file.fileName() );
 
766
  myQFileDialog->setMode(QFileDialog::AnyFile);
 
767
  myQFileDialog->setAcceptMode(QFileDialog::AcceptSave);
 
768
 
 
769
  int result = myQFileDialog->exec();
 
770
  raise ();
 
771
  
 
772
  if ( result != QDialog::Accepted) return;
 
773
  QString myOutputFileNameQString = myQFileDialog->selectedFile();
 
774
 
 
775
  if ( myOutputFileNameQString == "" ) return;
 
776
 
 
777
  myQSettings.writeEntry("/UI/lastSaveAsSvgFile", myOutputFileNameQString);
 
778
 
 
779
  mView->setCanvas(0);
 
780
  mComposition->setPlotStyle ( QgsComposition::Print );
 
781
 
 
782
  Q3Picture pic;
 
783
  QPainter p(&pic);
 
784
  mComposition->canvas()->drawArea ( QRect(0,0, 
 
785
        (int) (mComposition->paperWidth() * mComposition->scale()),
 
786
        (int) (mComposition->paperHeight() * mComposition->scale()) ), 
 
787
      &p, FALSE );
 
788
  p.end();
 
789
 
 
790
  mComposition->setPlotStyle ( QgsComposition::Preview );
 
791
  mView->setCanvas(mComposition->canvas());
 
792
 
 
793
  QRect br = pic.boundingRect();
 
794
 
 
795
  pic.save ( myOutputFileNameQString, "svg" );
 
796
}
 
797
 
 
798
void QgsComposer::setToolActionsOff(void)
 
799
{
 
800
  mActionOpenTemplate->setOn ( false );
 
801
  mActionSaveTemplateAs->setOn ( false );
 
802
  mActionExportAsImage->setOn ( false );
 
803
  mActionExportAsSVG->setOn ( false );
 
804
  mActionPrint->setOn ( false );
 
805
  mActionZoomAll->setOn ( false );
 
806
  mActionZoomIn->setOn ( false );
 
807
  mActionZoomOut->setOn ( false );
 
808
  mActionRefreshView->setOn ( false );
 
809
  mActionAddNewMap->setOn ( false );
 
810
  mActionAddImage->setOn ( false );
 
811
  mActionAddNewLabel->setOn ( false );
 
812
  mActionAddNewVectLegend->setOn ( false );
 
813
  mActionAddNewScalebar->setOn ( false );
 
814
  mActionSelectMoveItem->setOn ( false );
 
815
}
 
816
 
 
817
void QgsComposer::selectItem(void)
 
818
{
 
819
  mComposition->setTool ( QgsComposition::Select );
 
820
  setToolActionsOff();
 
821
  mActionSelectMoveItem->setOn ( true );
 
822
}
 
823
 
 
824
void QgsComposer::on_mActionSelectMoveItem_activated(void)
 
825
{
 
826
  selectItem();
 
827
}
 
828
 
 
829
void QgsComposer::on_mActionAddNewMap_activated(void)
 
830
{
 
831
  mComposition->setTool ( QgsComposition::AddMap );
 
832
  setToolActionsOff();
 
833
  mActionAddNewMap->setOn ( true );
 
834
}
 
835
 
 
836
void QgsComposer::on_mActionAddNewVectLegend_activated(void)
 
837
{
 
838
  mComposition->setTool ( QgsComposition::AddVectorLegend );
 
839
  setToolActionsOff();
 
840
  mActionAddNewVectLegend->setOn ( true );
 
841
}
 
842
 
 
843
void QgsComposer::on_mActionAddNewLabel_activated(void)
 
844
{
 
845
  mComposition->setTool ( QgsComposition::AddLabel );
 
846
  setToolActionsOff();
 
847
  mActionAddNewLabel->setOn ( true );
 
848
}
 
849
 
 
850
void QgsComposer::on_mActionAddNewScalebar_activated(void)
 
851
{
 
852
  mComposition->setTool ( QgsComposition::AddScalebar );
 
853
  setToolActionsOff();
 
854
  mActionAddNewScalebar->setOn ( true );
 
855
}
 
856
 
 
857
void QgsComposer::on_mActionAddImage_activated(void)
 
858
{
 
859
  mComposition->setTool ( QgsComposition::AddPicture );
 
860
  setToolActionsOff();
 
861
  mActionAddImage->setOn ( true );
 
862
}
 
863
 
 
864
void QgsComposer::moveEvent ( QMoveEvent *e ) { saveWindowState(); }
 
865
 
 
866
void QgsComposer::resizeEvent ( QResizeEvent *e )
 
867
{
 
868
  // Move size grip when window is resized
 
869
  mSizeGrip->move(rect().bottomRight() - mSizeGrip->rect().bottomRight());
 
870
 
 
871
  saveWindowState();
 
872
}
 
873
 
 
874
void QgsComposer::saveWindowState()
 
875
{
 
876
#ifdef QGISDEBUG
 
877
  std::cout << "QgsComposer::saveWindowState" << std::endl;
 
878
#endif
 
879
  QSettings settings;
 
880
 
 
881
  QPoint p = this->pos();
 
882
  QSize s = this->size();
 
883
 
 
884
  settings.writeEntry("/Composer/geometry/x", p.x());
 
885
  settings.writeEntry("/Composer/geometry/y", p.y());
 
886
  settings.writeEntry("/Composer/geometry/w", s.width());
 
887
  settings.writeEntry("/Composer/geometry/h", s.height());
 
888
 
 
889
  Q3ValueList<int> list = mSplitter->sizes();
 
890
  Q3ValueList<int>::Iterator it = list.begin();
 
891
  settings.writeEntry("/Composer/geometry/wiev", (int)(*it) );
 
892
  it++;
 
893
  settings.writeEntry("/Composer/geometry/options", (int)(*it) );
 
894
}
 
895
 
 
896
void QgsComposer::restoreWindowState()
 
897
{
 
898
  QSettings settings;
 
899
 
 
900
  QDesktopWidget *d = QApplication::desktop();
 
901
  int dw = d->width();
 
902
  int dh = d->height();
 
903
  int w = settings.readNumEntry("/Composer/geometry/w", 600);
 
904
  int h = settings.readNumEntry("/Composer/geometry/h", 400);
 
905
  int x = settings.readNumEntry("/Composer/geometry/x", (dw - 600) / 2);
 
906
  int y = settings.readNumEntry("/Composer/geometry/y", (dh - 400) / 2);
 
907
  resize(w, h);
 
908
  move(x, y);
 
909
 
 
910
  // This doesn't work
 
911
  Q3ValueList<int> list;
 
912
  w = settings.readNumEntry("/Composer/geometry/view", 300);
 
913
  list.push_back( w );
 
914
  w = settings.readNumEntry("/Composer/geometry/options", 300);
 
915
  list.push_back( w );
 
916
  mSplitter->setSizes ( list );
 
917
}
 
918
 
 
919
void QgsComposer::on_helpPButton_clicked()
 
920
{
 
921
  QgsContextHelp::run(context_id);
 
922
}
 
923
 
 
924
void QgsComposer::on_closePButton_clicked()
 
925
{
 
926
  close();
 
927
}
 
928
 
 
929
void QgsComposer::projectRead(void)
 
930
{
 
931
#ifdef QGISDEBUG
 
932
  std::cout << "QgsComposer::projectRead" << std::endl;
 
933
#endif
 
934
  if ( mComposition ) delete mComposition;
 
935
  mComposition  = new QgsComposition( this, 1 );
 
936
 
 
937
  // Read composition if it is defined in project
 
938
  QStringList l = QgsProject::instance()->subkeyList ( "Compositions", "" );
 
939
 
 
940
  bool found = false;
 
941
  for ( QStringList::iterator it = l.begin(); it != l.end(); ++it ) {
 
942
    std::cout << "key: " << (*it).toLocal8Bit().data() << std::endl;
 
943
    if ( (*it).compare ( "composition_1" ) == 0 ) {
 
944
      found = true;
 
945
      break;
 
946
    }
 
947
  }
 
948
 
 
949
  if ( found ) {
 
950
    mComposition->readSettings ( );
 
951
    mFirstTime = false;
 
952
  } else { 
 
953
    if ( isVisible() ) {
 
954
      mComposition->createDefault();
 
955
      mFirstTime = false;
 
956
    } else {
 
957
      mFirstTime = true;
 
958
    }
 
959
  }
 
960
 
 
961
  mComposition->setActive ( true );
 
962
}
 
963
 
 
964
void QgsComposer::newProject(void)
 
965
{
 
966
#ifdef QGISDEBUG
 
967
  std::cout << "QgsComposer::newProject" << std::endl;
 
968
#endif
 
969
  if ( mComposition ) delete mComposition;
 
970
 
 
971
  mComposition  = new QgsComposition( this, 1 );
 
972
  mComposition->setActive ( true );
 
973
 
 
974
  // If composer is visible, create default immediately, otherwise wait for the first open()
 
975
  if ( isVisible() ) {
 
976
    mComposition->createDefault();
 
977
    mFirstTime = false;
 
978
  } else {
 
979
    mFirstTime = true;
 
980
  }
 
981
}
 
982
 
 
983
bool QgsComposer::writeSettings ( void )
 
984
{
 
985
#ifdef WIN32
 
986
  bool ok = true;
 
987
#else
 
988
  bool ok = false;
 
989
#endif
 
990
  return ok;
 
991
}
 
992
 
 
993
bool QgsComposer::readSettings ( void )
 
994
{
 
995
#ifdef WIN32
 
996
  bool ok = true;
 
997
#else
 
998
  bool ok = false;
 
999
#endif
 
1000
  return ok;
 
1001
}
 
1002
 
 
1003
bool QgsComposer::writeXML( QDomNode & node, QDomDocument & doc )
 
1004
{
 
1005
#ifdef QGISDEBUG
 
1006
  std::cout << "QgsComposer::writeXML" << std::endl;
 
1007
#endif
 
1008
  QDomElement compositionsNode = doc.createElement("compositions");
 
1009
 
 
1010
  node.appendChild( compositionsNode );
 
1011
 
 
1012
  return true;
 
1013
}
 
1014
 
 
1015
bool QgsComposer::readXML( QDomNode & node )
 
1016
{
 
1017
#ifdef QGISDEBUG
 
1018
  std::cout << "QgsComposer::readXML" << std::endl;
 
1019
#endif
 
1020
  return true;
 
1021
}
 
1022