Scribus Developer Documentation - API
logo-pen

Scribus Developer Documentation - API

wmfimport.cpp

Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 
00008 /* Code inspired by KOffice libwmf and adapted for Scribus by Jean Ghali */
00009 
00010 #include "scconfig.h"
00011 #include "wmfimport.h"
00012 
00013 #include <QCursor>
00014 #include <QDrag>
00015 #include <QBuffer>
00016 #include <QDataStream>
00017 #include <QFile>
00018 #include <QMimeData>
00019 #include <QPainterPath>
00020 #include <QRegExp>
00021 
00022 #include "customfdialog.h"
00023 #include "scribus.h"
00024 #include "scribusXml.h"
00025 #include "propertiespalette.h"
00026 #include "prefsfile.h"
00027 
00028 #include <cmath>
00029 #include "commonstrings.h"
00030 #include "fpointarray.h"
00031 #include "menumanager.h"
00032 #include "prefsmanager.h"
00033 #include "pageitem.h"
00034 #include "scraction.h"
00035 #include "scribuscore.h"
00036 #include "scribusdoc.h"
00037 #include "selection.h"
00038 #include "undomanager.h"
00039 #include "loadsaveplugin.h"
00040 #include "util.h"
00041 #include "util_icon.h"
00042 #include "util_math.h"
00043 #include "fonts/scfontmetrics.h"
00044 
00045 using namespace std;
00046 
00047 #include "wmfstruct.h"
00048 #include "wmfcmd.h"
00049 #include "wmfcontext.h"
00050 #include "wmfhandle.h"
00051 #include "metafuncs.h"
00052 
00053 #define WMFIMPORT_DEBUG 1
00054 #define MAX_OBJHANDLE   128
00055 
00056 #define ANSI_CHARSET            0       // ANSI charset (Windows-1252)
00057 #define DEFAULT_CHARSET         1
00058 #define SYMBOL_CHARSET          2
00059 #define MAC_CHARSET             77
00060 #define SHIFTJIS_CHARSET        128     // Shift JIS charset    (Windows-932)
00061 #define HANGEUL_CHARSET         129     // Hangeul charset      (Windows-949)
00062 #define JOHAB_CHARSET           130     // Johab charset        (Windows-1361)
00063 #define GB2312_CHARSET          134     // GB2312 charset       (Windows-936)
00064 #define CHINESEBIG5_CHARSET     136     // Chinese Big5 charset (Windows-950)
00065 #define GREEK_CHARSET           161     // Greek charset        (Windows-1253)
00066 #define TURKISH_CHARSET         162     // Turkish charset      (Windows-1254)
00067 #define VIETNAMESE_CHARSET      163     // Vietnamese charset   (Windows-1258)
00068 #define HEBREW_CHARSET          177     // Hebrew charset       (Windows-1255)
00069 #define ARABIC_CHARSET          178     // Arabic charset       (Windows-1256)
00070 #define BALTIC_CHARSET          186     // Baltic charset       (Windows-1257)
00071 #define RUSSIAN_CHARSET         204     // Cyrillic charset     (Windows-1251)
00072 #define THAI_CHARSET            222     // Thai charset         (Windows-874)
00073 #define EASTEUROPE_CHARSET      238     // Eastern european charset (Windows-1250)
00074 #define OEM_CHARSET             255
00075 
00076 /* Symbol to unicode conversion table copied from http://root.cern.ch/viewvc/trunk/qt/src/TQtSymbolCodec.cxx
00077 This code is placed under GPL licence (http://root.cern.ch/viewvc/trunk/LICENSE) */
00078 static const ushort greek_symbol_to_unicode[64] = {
00079 //
00080 //  upper case letters:
00081 //  ----------------
00082 //   Alpha   Beta     Chi   Delta   Epsilon   Phi    Gamma    Eta
00083     0x0391, 0x0392, 0x03A7, 0x0394, 0x0395, 0x03A6, 0x0393, 0x0397,
00084 //   Iota   Theta(S) Kappa  Lambda    Mu      Nu    Omicron   Pi
00085     0x0399, 0x03D1, 0x039A, 0x039B, 0x039C, 0x039D, 0x039F, 0x03A0,
00086 //  Theta    Rho    Sigma    Tau    Upsilon Stigma   Omega     Xi
00087     0x0398, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03DB, 0x03A9, 0x039E,
00088 //   Psi     Zeta   Sigma    Tau    Upsilon  ????   Omega     Xi
00089     0x03A8, 0x0396, 0x03EA, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
00090 //
00091 //  lower case letters:
00092 //  ----------------
00093 //   Alpha   Beta    Chi    Delta   Epsilon   Phi    Gamma    Eta
00094     0x03B1, 0x03B2, 0x03C7, 0x03B4, 0x03B5, 0x03D5, 0x03B3, 0x03B7,
00095 //   Iota   Phi (2) Kappa   Lambda    Mu      Nu    Omicron   Pi
00096     0x03B9, 0x03C6, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF, 0x03C0,
00097 //  Theta    Rho    Sigma    Tau    Upsilon OmegaPi Omega     Xi
00098     0x03B8, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03D6, 0x03B9, 0x03BE,
00099 //   Psi     Zeta   Sigma    Tau    Upsilon  ????   Omega     Xi
00100     0x03C8, 0x03B6, 0x03EA, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD
00101 };
00102 
00103 /* Symbol to unicode conversion table copied from http://root.cern.ch/viewvc/trunk/qt/src/TQtSymbolCodec.cxx
00104 This code is placed under GPL licence (http://root.cern.ch/viewvc/trunk/LICENSE) */
00105 static const ushort symbol_to_unicode[96] = {
00106 //
00107 //  upper case letters:
00108 //  ----------------
00109 // UPSILON  NUMBER  LessEq   Div   INFINITY ???????  CLUB   DIAMOND     
00110     0x03D2, 0x0374, 0x2264, 0x2215, 0x221E, 0x0395, 0x2663, 0x2666,
00111 //   HEART  SPADE   <--->   <---             -->             RING
00112     0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193, 0x2218,
00113 //  Theta    Rho    Great    ????   Propor  diff    bullet   ????
00114     0x0398, 0x03A1, 0x2265, 0x03A4, 0x221D, 0x2202, 0x2219, 0x03A8,
00115 //   NonEq  Ident    ????   ellips   div     minus  ?????   aleph
00116     0x2260, 0x2261, 0xFFFD, 0x22EF, 0x2223, 0x2212, 0xFFFD, 0xFFFD,
00117 //
00118 //  lower case letters:
00119 //  ----------------
00120 //   Alpha   Beta    Chi    Delta   Epsilon   Phi    Gamma    Eta
00121     0x03B1, 0x03B2, 0x03C7, 0x03B4, 0x03B5, 0x03D5, 0x03B3, 0x03B7,
00122 //   Iota   Phi (2) Kappa   Lambda    Mu      Nu    Omicron   Pi
00123     0x03B9, 0x03C6, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF, 0x03C0,
00124 //  Theta    Rho    Sigma    Tau    Upsilon OmegaPi Omega     Xi
00125     0x03B8, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03D6, 0x03B9, 0x03BE,
00126 //   Psi     Zeta   arrow    Tau    Upsilon  ????   Omega     Xi
00127     0x03C8, 0x03B6, 0x21D4, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
00128 //  lower case letters:
00129 //  ----------------
00130 //   Alpha   Beta    Chi    Delta   Sigma     Phi    Gamma    Eta
00131     0x03B1, 0x03B2, 0x03C7, 0x03B4, 0x2211, 0x03D5, 0x03B3, 0x03B7,
00132 //   Iota   Phi (2) Kappa   Lambda    Mu      Nu    Omicron   Pi
00133     0x03B9, 0x03C6, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF, 0x03C0,
00134 //  Theta   Integr  Sigma    Tau    Upsilon OmegaPi Omega     Xi
00135     0x03B8, 0x222b, 0x03C3, 0x03C4, 0x03C5, 0x03D6, 0x03B9, 0x03BE,
00136 //   Psi     Zeta   Sigma    Tau    Upsilon  ????   Omega     Xi
00137     0x03C8, 0x03B6, 0x03EA, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD
00138 };
00139 
00140 WMFImport::WMFImport( ScribusMainWindow* mw, int flags ) :
00141     QObject(mw)
00142 {   
00143     m_tmpSel = new Selection(this, false);
00144     m_Doc    = mw->doc;
00145     unsupported = false;
00146     importFailed = false;
00147     importCanceled = true;
00148     importedColors.clear();
00149     m_docDesc = "";
00150     m_docTitle = "";
00151     interactive = (flags & LoadSavePlugin::lfInteractive);
00152 
00153     m_Valid        = false;
00154     m_ObjHandleTab = NULL;
00155     m_Dpi          = 1440;
00156 }
00157 
00158 WMFImport::~WMFImport()
00159 {
00160     qDeleteAll(m_commands);
00161     m_commands.clear();
00162     if ( m_tmpSel) delete m_tmpSel;
00163     if ( m_ObjHandleTab ) 
00164     {
00165         for (int i = 0; i < MAX_OBJHANDLE; ++i)
00166         {
00167             if (m_ObjHandleTab[i])
00168                 delete m_ObjHandleTab[i];
00169         }
00170         delete[] m_ObjHandleTab;
00171     }
00172 }
00173 
00174 QString WMFImport::importColor(const QColor& color)
00175 {
00176     bool found = false;
00177     int r, g, b;
00178     QColor  tmpColor;
00179     QString retColorName;
00180     ColorList::Iterator it;
00181     for (it = m_Doc->PageColors.begin(); it != m_Doc->PageColors.end(); ++it)
00182     {
00183         if (it.value().getColorModel() == colorModelRGB)
00184         {
00185             it.value().getRGB(&r, &g, &b);
00186             tmpColor.setRgb(r, g, b);
00187             if (color == tmpColor)
00188             {
00189                 retColorName = it.key();
00190                 found = true;
00191             }
00192         }
00193     }
00194     if (!found)
00195     {
00196         ScColor tmp;
00197         tmp.fromQColor(color);
00198         tmp.setSpotColor(false);
00199         tmp.setRegistrationColor(false);
00200         m_Doc->PageColors.insert("FromWMF"+color.name(), tmp);
00201         importedColors.append("FromWMF"+color.name());
00202         retColorName = "FromWMF"+color.name();
00203     }
00204     return retColorName;
00205 }
00206 
00207 QColor WMFImport::colorFromParam( short* params )
00208 {
00209     unsigned int colorRef;
00210     int red, green, blue;
00211 
00212     colorRef = toDWord( params ) & 0xffffff;
00213     red      = colorRef & 255;
00214     green    = ( colorRef>>8 ) & 255;
00215     blue     = ( colorRef>>16 ) & 255;
00216 
00217     return QColor( red, green, blue );
00218 }
00219 
00220 QTextCodec* WMFImport::codecFromCharset( int charset )
00221 {
00222     QTextCodec* codec = NULL;
00223     if (charset == DEFAULT_CHARSET || charset == OEM_CHARSET)
00224         codec = QTextCodec::codecForLocale();
00225     else if (charset == ANSI_CHARSET)
00226         codec = QTextCodec::codecForName("windows-1252");
00227     /*else if (charset == SYMBOL_CHARSET)
00228         codec = QTextCodec::codecForLocale();// Not supported yet*/
00229     else if (charset == MAC_CHARSET)
00230         codec = QTextCodec::codecForName("Apple Roman");
00231     else if (charset == SHIFTJIS_CHARSET)
00232         codec = QTextCodec::codecForName("Shift-JIS");
00233     else if (charset == HANGEUL_CHARSET)
00234         codec = QTextCodec::codecForName("CP949");
00235     else if (charset == GB2312_CHARSET)
00236         codec = QTextCodec::codecForName("CP936");
00237     else if (charset == CHINESEBIG5_CHARSET)
00238         codec = QTextCodec::codecForName("Big5");
00239     else if (charset == GREEK_CHARSET)
00240         codec = QTextCodec::codecForName("windows-1253");
00241     else if (charset == TURKISH_CHARSET)
00242         codec = QTextCodec::codecForName("windows-1254");
00243     else if (charset == VIETNAMESE_CHARSET)
00244         codec = QTextCodec::codecForName("windows-1258");
00245     else if (charset == HEBREW_CHARSET)
00246         codec = QTextCodec::codecForName("windows-1255");
00247     else if (charset == ARABIC_CHARSET)
00248         codec = QTextCodec::codecForName("windows-1256");
00249     else if (charset == BALTIC_CHARSET)
00250         codec = QTextCodec::codecForName("windows-1257");
00251     else if (charset == RUSSIAN_CHARSET)
00252         codec = QTextCodec::codecForName("windows-1251");
00253     else if (charset == THAI_CHARSET)
00254         codec = QTextCodec::codecForName("CP874");
00255     else if (charset == EASTEUROPE_CHARSET)
00256         codec = QTextCodec::codecForName("windows-1250");
00257     return codec;
00258 }
00259 
00260 QString WMFImport::symbolToUnicode ( const QByteArray& chars )
00261 {
00262     /*Code under GPL licence (http://root.cern.ch/viewvc/trunk/LICENSE)
00263     taken from http://root.cern.ch/viewvc/trunk/qt/src/TQtSymbolCodec.cxx*/
00264     QString r;
00265     const unsigned char * c = (const unsigned char *) chars.data();
00266     
00267     if( chars.size() == 0 ) return r;
00268     
00269     for (int i = 0; i < chars.size(); ++i) 
00270     {
00271         if ( 64 < c[i] && c[i] <= 64+32 )
00272             r.append( QChar(greek_symbol_to_unicode[c[i]-65]) );
00273         else if (64+32+1 <= c[i] && c[i] < 64+32+32+1)
00274             r.append( QChar(greek_symbol_to_unicode[c[i]-65-32]+32) );
00275         else if (161 <= c[i] )
00276             r.append(  QChar(symbol_to_unicode[c[i]-161]) );
00277         else
00278             r.append( QChar(c[i]) );
00279     }
00280     return r;
00281 }
00282 
00283 FPointArray WMFImport::pointsFromParam( short num, short* params )
00284 {
00285     FPointArray points;
00286     points.resize( num );
00287 
00288     for ( int i = 0; i < num; i++, params += 2 )
00289         points.setPoint( i, params[ 0 ], params[ 1 ] );
00290 
00291     return points;
00292 }
00293 
00294 FPointArray WMFImport::pointsToPolyline( const FPointArray& points, bool closePath )
00295 {
00296     bool bFirst = true;
00297     double x = 0.0, y = 0.0;
00298     FPointArray polyline;
00299     polyline.svgInit();
00300     for( uint i = 0; i < points.size(); ++i )
00301     {
00302         FPoint point = points.point(i);
00303         if( bFirst )
00304         {
00305             x = point.x();
00306             y = point.y();
00307             polyline.svgMoveTo(x, y);
00308             bFirst = false;
00309         }
00310         else
00311         {
00312             x = point.x();
00313             y = point.y();
00314             polyline.svgLineTo(x, y);
00315         }
00316     }
00317     if (closePath && (points.size() > 4))
00318         polyline.svgClosePath();
00319     return polyline;
00320 }
00321 
00322 void WMFImport::pointsToAngle( double xStart, double yStart, double xEnd, double yEnd, double& angleStart, double& angleLength )
00323 {
00324     double aStart  = atan2( yStart,  xStart );
00325     double aLength = atan2( yEnd, xEnd ) - aStart;
00326 
00327     angleStart  = (int)(aStart * 180.0 / 3.14166);
00328     angleLength = (int)(aLength * 180.0 / 3.14166);
00329     if ( angleLength < 0 ) angleLength = 360.0 + angleLength;
00330 }
00331 
00332 bool WMFImport::import(QString fname, int flags)
00333 {
00334     if (!loadWMF(fname))
00335     {
00336         importFailed = true;
00337         return false;
00338     }
00339     QString CurDirP = QDir::currentPath();
00340     QFileInfo efp(fname);
00341     QDir::setCurrent(efp.path());
00342     importWMF(flags);
00343     QDir::setCurrent(CurDirP);
00344     return true;
00345 }
00346 
00347 bool WMFImport::loadWMF( const QString &fileName )
00348 {
00349     QFile file( fileName );
00350 
00351     if ( !file.exists() )
00352     {
00353         cerr << "File " << QFile::encodeName(fileName).data() << " does not exist" << endl;
00354         return false;
00355     }
00356 
00357     if ( !file.open( QIODevice::ReadOnly ) )
00358     {
00359         cerr << "Cannot open file " << QFile::encodeName(fileName).data() << endl;
00360         return false;
00361     }
00362 
00363     QByteArray ba = file.readAll();
00364     file.close();
00365 
00366     QBuffer buffer( &ba );
00367     buffer.open( QIODevice::ReadOnly );
00368     return loadWMF( buffer );
00369 }
00370 
00371 bool WMFImport::loadWMF( QBuffer &buffer )
00372 {
00373     QDataStream st;
00374     WmfEnhMetaHeader eheader;
00375     WmfMetaHeader header;
00376     WmfPlaceableHeader pheader;
00377     WORD16 checksum;
00378     int filePos, idx, i;
00379     WmfCmd *cmd;
00380     WORD32 rdSize;
00381     WORD16 rdFunc;
00382 
00383     header.mtSize = 0;
00384     header.mtHeaderSize = 0;
00385     header.mtNoParameters = 0;
00386 
00387     qDeleteAll(m_commands);
00388     m_commands.clear();
00389 
00390     st.setDevice( &buffer );
00391     st.setByteOrder( QDataStream::LittleEndian ); // Great, I love Qt !
00392 
00393     //----- Read placeable metafile header
00394     st >> pheader.key;
00395     m_IsPlaceable = ( pheader.key==( DWORD )APMHEADER_KEY );
00396     if ( m_IsPlaceable )
00397     {
00398         st >> pheader.hmf;
00399         st >> pheader.bbox.left;
00400         st >> pheader.bbox.top;
00401         st >> pheader.bbox.right;
00402         st >> pheader.bbox.bottom;
00403         st >> pheader.inch;
00404         st >> pheader.reserved;
00405         st >> pheader.checksum;
00406         checksum = calcCheckSum( &pheader );
00407         if ( pheader.checksum!=checksum ) m_IsPlaceable = false;
00408 
00409         m_Dpi = pheader.inch;
00410         m_BBox.setLeft( pheader.bbox.left );
00411         m_BBox.setTop( pheader.bbox.top );
00412         m_BBox.setRight( pheader.bbox.right );
00413         m_BBox.setBottom( pheader.bbox.bottom );
00414         m_HeaderBoundingBox = m_BBox;
00415         if ( WMFIMPORT_DEBUG )
00416         {
00417             cerr << endl << "-------------------------------------------------" << endl;
00418             cerr << "WMF Placeable Header ( " << static_cast<int>(sizeof( pheader ) ) << "):" << endl;
00419             cerr << "  bbox=( " << m_BBox.left() << "; " << m_BBox.top() << "; " << m_BBox.width() << "; " << m_BBox.height() << ")" << endl;
00420             cerr << "  inch=" << pheader.inch << endl;
00421             cerr << "  checksum=" << pheader.checksum << "( " << (pheader.checksum==checksum?"ok":"wrong") << " )" << endl;
00422         }
00423     }
00424     else buffer.seek( 0 );
00425 
00426     //----- Read as enhanced metafile header
00427     filePos = buffer.pos();
00428     st >> eheader.iType;
00429     st >> eheader.nSize;
00430     st >> eheader.rclBounds.left;
00431     st >> eheader.rclBounds.top;
00432     st >> eheader.rclBounds.right;
00433     st >> eheader.rclBounds.bottom;
00434     st >> eheader.rclFrame.left;
00435     st >> eheader.rclFrame.top;
00436     st >> eheader.rclFrame.right;
00437     st >> eheader.rclFrame.bottom;
00438     st >> eheader.dSignature;
00439     m_IsEnhanced = ( eheader.dSignature==ENHMETA_SIGNATURE );
00440     if ( m_IsEnhanced ) // is it really enhanced ?
00441     {
00442         st >> eheader.nVersion;
00443         st >> eheader.nBytes;
00444         st >> eheader.nRecords;
00445         st >> eheader.nHandles;
00446         st >> eheader.sReserved;
00447         st >> eheader.nDescription;
00448         st >> eheader.offDescription;
00449         st >> eheader.nPalEntries;
00450         st >> eheader.szlDevice.width;
00451         st >> eheader.szlDevice.height;
00452         st >> eheader.szlMillimeters.width;
00453         st >> eheader.szlMillimeters.height;
00454 
00455         if ( WMFIMPORT_DEBUG )
00456         {
00457             cerr << endl << "-------------------------------------------------" << endl;
00458             cerr << "WMF Extended Header:" << endl;
00459             cerr << "  iType=" << eheader.iType << endl;
00460             cerr << "  nSize=" << eheader.nSize << endl;
00461             cerr << "  rclBounds=( " << eheader.rclBounds.left << "; " << eheader.rclBounds.top << "; "
00462                       << eheader.rclBounds.right << "; " << eheader.rclBounds.bottom << ")" << endl;
00463             cerr << "  rclFrame=( " << eheader.rclFrame.left << "; " << eheader.rclFrame.top << "; "
00464                       << eheader.rclFrame.right << "; " << eheader.rclFrame.bottom << ")" << endl;
00465             cerr << "  nBytes=" << eheader.nBytes << endl;
00466             cerr << "\nNOT YET IMPLEMENTED, SORRY." << endl;
00467         }
00468     }
00469     else // no, not enhanced
00470     {
00471         //----- Read as standard metafile header
00472         buffer.seek( filePos );
00473         st >> header.mtType;
00474         st >> header.mtHeaderSize;
00475         st >> header.mtVersion;
00476         st >> header.mtSize;
00477         st >> header.mtNoObjects;
00478         st >> header.mtMaxRecord;
00479         st >> header.mtNoParameters;
00480         if ( WMFIMPORT_DEBUG ) {
00481             cerr << "WMF Header: " <<  "mtSize=" << header.mtSize << endl;
00482         }
00483     }
00484 
00485     //----- Test header validity
00486     m_Valid = ((header.mtHeaderSize == 9) && (header.mtNoParameters == 0)) || m_IsEnhanced || m_IsPlaceable;
00487     if ( m_Valid )
00488     {
00489         //----- Read Metafile Records
00490         rdFunc = -1;
00491         while ( !st.atEnd() && (rdFunc != 0) )
00492         {
00493             st >> rdSize;
00494             st >> rdFunc;
00495             idx = findFunc( rdFunc );
00496             rdSize -= 3;
00497 
00498             cmd = new WmfCmd;
00499             m_commands.append(cmd);
00500 
00501             cmd->funcIndex = idx;
00502             cmd->numParam = rdSize;
00503             cmd->params = new WORD16[ rdSize ];
00504 
00505             for ( i=0; i<rdSize && !st.atEnd(); i++ )
00506                 st >> cmd->params[ i ];
00507 
00508 
00509             if ( rdFunc == 0x020B && !m_IsPlaceable) {         // SETWINDOWORG: dimensions
00510                 m_BBox.setLeft( qMin((int) cmd->params[ 1 ], m_BBox.left()) );
00511                 m_BBox.setTop ( qMin((int) cmd->params[ 0 ], m_BBox.top()) );
00512             }
00513             if ( rdFunc == 0x020C && !m_IsPlaceable ) {         // SETWINDOWEXT: dimensions
00514                 m_BBox.setWidth ( qMax((int) cmd->params[ 1 ], m_BBox.width()) );
00515                 m_BBox.setHeight( qMax((int) cmd->params[ 0 ], m_BBox.height()));
00516             }
00517 
00518             if ( i<rdSize )
00519             {
00520                 cerr << "WMF : file truncated !" << endl;
00521                 return false;
00522             }
00523         }
00524         //----- Test records validities
00525         m_Valid = (rdFunc == 0) && (m_BBox.width() != 0) && (m_BBox.height() != 0);
00526         if ( !m_Valid ) {
00527             cerr << "WMF : incorrect file format !" << endl;
00528         }
00529     }
00530     else {
00531         cerr << "WMF Header : incorrect header !" << endl;
00532     }
00533 
00534     buffer.close();
00535     return m_Valid;
00536 }
00537 
00538 bool WMFImport::importWMF(int flags)
00539 {
00540     bool ret = false;
00541     //double scale = (m_Dpi > 288) ? 288.0 / m_Dpi : 1.0;
00542     double scale  = (m_Dpi > 0) ? 72.0 / m_Dpi : 0.05;
00543     double width  = m_BBox.width() * scale;
00544     double height = m_BBox.height() * scale;
00545     if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
00546     {
00547         m_Doc->setPage(fabs(width), fabs(height), 0, 0, 0, 0, 0, 0, false, false);
00548         m_Doc->addPage(0);
00549         m_Doc->view()->addPage(0);
00550     }
00551     else
00552     {
00553         if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
00554         {
00555             m_Doc=ScCore->primaryMainWindow()->doFileNew(fabs(width), fabs(height), 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
00556             ScCore->primaryMainWindow()->HaveNewDoc();
00557             ret = true;
00558         }
00559     }
00560     if ((ret) || (!interactive))
00561     {
00562         if (width > height)
00563             m_Doc->PageOri = 1;
00564         else
00565             m_Doc->PageOri = 0;
00566         m_Doc->m_pageSize = "Custom";
00567     }
00568     FPoint minSize = m_Doc->minCanvasCoordinate;
00569     FPoint maxSize = m_Doc->maxCanvasCoordinate;
00570     FPoint cOrigin = m_Doc->view()->canvasOrigin();
00571     m_Doc->view()->Deselect();
00572     m_Doc->setLoading(true);
00573     m_Doc->DoDrawing = false;
00574     m_Doc->view()->updatesOn(false);
00575     m_Doc->scMW()->ScriptRunning = true;
00576     qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
00577     //gc->Family = m_Doc->toolSettings.defFont;
00578     m_Doc->PageColors.ensureBlackAndWhite();
00579     //m_gc.push( gc );
00580     QList<PageItem*> Elements = parseWmfCommands();
00581     if (flags & LoadSavePlugin::lfCreateDoc)
00582     {
00583         m_Doc->documentInfo.setTitle(m_docTitle);
00584         m_Doc->documentInfo.setComments(m_docDesc);
00585     }
00586     m_tmpSel->clear();
00587     if (Elements.count() == 0)
00588     {
00589         importFailed = true;
00590         if (importedColors.count() != 0)
00591         {
00592             for (int cd = 0; cd < importedColors.count(); cd++)
00593             {
00594                 m_Doc->PageColors.remove(importedColors[cd]);
00595             }
00596         }
00597     }
00598     if (Elements.count() > 1)
00599     {
00600         bool isGroup = true;
00601         int firstElem = -1;
00602         if (Elements.at(0)->Groups.count() != 0)
00603             firstElem = Elements.at(0)->Groups.top();
00604         for (int bx = 0; bx < Elements.count(); ++bx)
00605         {
00606             PageItem* bxi = Elements.at(bx);
00607             if (bxi->Groups.count() != 0)
00608             {
00609                 if (bxi->Groups.top() != firstElem)
00610                     isGroup = false;
00611             }
00612             else
00613                 isGroup = false;
00614         }
00615         if (!isGroup)
00616         {
00617             double minx = 99999.9;
00618             double miny = 99999.9;
00619             double maxx = -99999.9;
00620             double maxy = -99999.9;
00621             uint lowestItem = 999999;
00622             uint highestItem = 0;
00623             for (int a = 0; a < Elements.count(); ++a)
00624             {
00625                 Elements.at(a)->Groups.push(m_Doc->GroupCounter);
00626                 PageItem* currItem = Elements.at(a);
00627                 lowestItem = qMin(lowestItem, currItem->ItemNr);
00628                 highestItem = qMax(highestItem, currItem->ItemNr);
00629                 double lw = currItem->lineWidth() / 2.0;
00630                 if (currItem->rotation() != 0)
00631                 {
00632                     FPointArray pb;
00633                     pb.resize(0);
00634                     pb.addPoint(FPoint(currItem->xPos()-lw, currItem->yPos()-lw));
00635                     pb.addPoint(FPoint(currItem->width()+lw*2.0, -lw, currItem->xPos()-lw, currItem->yPos()-lw, currItem->rotation(), 1.0, 1.0));
00636                     pb.addPoint(FPoint(currItem->width()+lw*2.0, currItem->height()+lw*2.0, currItem->xPos()-lw, currItem->yPos()-lw, currItem->rotation(), 1.0, 1.0));
00637                     pb.addPoint(FPoint(-lw, currItem->height()+lw*2.0, currItem->xPos()-lw, currItem->yPos()-lw, currItem->rotation(), 1.0, 1.0));
00638                     for (uint pc = 0; pc < 4; ++pc)
00639                     {
00640                         minx = qMin(minx, pb.point(pc).x());
00641                         miny = qMin(miny, pb.point(pc).y());
00642                         maxx = qMax(maxx, pb.point(pc).x());
00643                         maxy = qMax(maxy, pb.point(pc).y());
00644                     }
00645                 }
00646                 else
00647                 {
00648                     minx = qMin(minx, currItem->xPos()-lw);
00649                     miny = qMin(miny, currItem->yPos()-lw);
00650                     maxx = qMax(maxx, currItem->xPos()-lw + currItem->width()+lw*2.0);
00651                     maxy = qMax(maxy, currItem->yPos()-lw + currItem->height()+lw*2.0);
00652                 }
00653             }
00654             double gx = minx;
00655             double gy = miny;
00656             double gw = maxx - minx;
00657             double gh = maxy - miny;
00658             PageItem *high = m_Doc->Items->at(highestItem);
00659             int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, gx, gy, gw, gh, 0, m_Doc->toolSettings.dBrush, m_Doc->toolSettings.dPen, true);
00660             PageItem *neu = m_Doc->Items->takeAt(z);
00661             m_Doc->Items->insert(lowestItem, neu);
00662             neu->Groups.push(m_Doc->GroupCounter);
00663             neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
00664             neu->isGroupControl = true;
00665             neu->groupsLastItem = high;
00666             for (int a = 0; a < m_Doc->Items->count(); ++a)
00667             {
00668                 m_Doc->Items->at(a)->ItemNr = a;
00669             }
00670             neu->setRedrawBounding();
00671             neu->setTextFlowMode(PageItem::TextFlowUsesFrameShape);
00672             Elements.prepend(neu);
00673             m_Doc->GroupCounter++;
00674         }
00675     }
00676     m_Doc->DoDrawing = true;
00677     m_Doc->scMW()->ScriptRunning = false;
00678     if (interactive)
00679         m_Doc->setLoading(false);
00680     qApp->setOverrideCursor(QCursor(Qt::ArrowCursor));
00681     if ((Elements.count() > 0) && (!ret) && (interactive))
00682     {
00683         if (flags & LoadSavePlugin::lfScripted)
00684         {
00685             bool loadF = m_Doc->isLoading();
00686             m_Doc->setLoading(false);
00687             m_Doc->changed();
00688             m_Doc->setLoading(loadF);
00689             for (int dre=0; dre<Elements.count(); ++dre)
00690             {
00691                 m_Doc->m_Selection->addItem(Elements.at(dre), true);
00692             }
00693             m_Doc->m_Selection->setGroupRect();
00694             m_Doc->view()->updatesOn(true);
00695             importCanceled = false;
00696         }
00697         else
00698         {
00699             m_Doc->DragP = true;
00700             m_Doc->DraggedElem = 0;
00701             m_Doc->DragElements.clear();
00702             for (int dre=0; dre<Elements.count(); ++dre)
00703             {
00704                 m_Doc->DragElements.append(Elements.at(dre)->ItemNr);
00705                 m_tmpSel->addItem(Elements.at(dre), true);
00706             }
00707             ScriXmlDoc *ss = new ScriXmlDoc();
00708             m_tmpSel->setGroupRect();
00709             QMimeData* md = new QMimeData();
00710             md->setText(ss->WriteElem(m_Doc, m_Doc->view(), m_tmpSel));
00711             QDrag* dr = new QDrag(m_Doc->view()->viewport());
00712             dr->setMimeData(md);
00713 #ifndef QT_MAC
00714 // see #2526
00715             m_Doc->itemSelection_DeleteItem(m_tmpSel);
00716 #endif
00717 //          m_Doc->view()->resizeContents(qRound((maxSize.x() - minSize.x()) * m_Doc->view()->scale()), qRound((maxSize.y() - minSize.y()) * m_Doc->view()->scale()));
00718 //          m_Doc->view()->scrollBy(qRound((m_Doc->minCanvasCoordinate.x() - minSize.x()) * m_Doc->view()->scale()), qRound((m_Doc->minCanvasCoordinate.y() - minSize.y()) * m_Doc->view()->scale()));
00719             m_Doc->minCanvasCoordinate = minSize;
00720             m_Doc->maxCanvasCoordinate = maxSize;
00721             m_Doc->view()->adjustCanvas(qRound((maxSize.x() - minSize.x()) * m_Doc->view()->scale()), qRound((maxSize.y() - minSize.y()) * m_Doc->view()->scale()), 0, 0);
00722             m_Doc->view()->setCanvasOrigin(cOrigin.x(), cOrigin.y());
00723             m_Doc->view()->updatesOn(true);
00724         //  dr->setPixmap(loadIcon("DragPix.xpm"));
00725             const QPixmap& dragCursor = loadIcon("DragPix.xpm");
00726             dr->setDragCursor(dragCursor, Qt::CopyAction);
00727             dr->setDragCursor(dragCursor, Qt::MoveAction);
00728             dr->setDragCursor(dragCursor, Qt::LinkAction);
00729             dr->exec();
00730             delete ss;
00731             m_Doc->DragP = false;
00732             m_Doc->DraggedElem = 0;
00733             m_Doc->DragElements.clear();
00734         }
00735     }
00736     else
00737     {
00738         bool loadF = m_Doc->isLoading();
00739         m_Doc->setLoading(false);
00740         m_Doc->changed();
00741         m_Doc->reformPages();
00742         m_Doc->view()->updatesOn(true);
00743         m_Doc->setLoading(loadF);
00744     }
00745     return true;
00746 }
00747 
00748 QList<PageItem*> WMFImport::parseWmfCommands(void)
00749 {
00750     int idx, i;
00751     const WmfCmd* cmd;
00752     QList<PageItem*> elements;
00753 
00754     m_context.reset();
00755 
00756     if ( !m_Valid )  return elements;
00757 
00758     if ( m_ObjHandleTab ) delete[] m_ObjHandleTab;
00759     m_ObjHandleTab = new WmfObjHandle* [ MAX_OBJHANDLE ];
00760     for ( i = MAX_OBJHANDLE-1; i >= 0; i-- )
00761         m_ObjHandleTab[ i ] = NULL;
00762 
00763     if ( WMFIMPORT_DEBUG )  {
00764         cerr << "Bounding box : " << m_BBox.left() << " " << m_BBox.top() << " " << m_BBox.right() << " " << m_BBox.bottom() << endl;
00765     }
00766 
00767     double scale  = (m_Dpi > 0) ? 72.0 / m_Dpi : 0.05;
00768     m_context.setViewportOrg( 0, 0 );
00769     m_context.setViewportExt( m_BBox.width() * scale, m_BBox.height() * scale );
00770     m_context.setWindowOrg( m_BBox.left(), m_BBox.bottom() );
00771     m_context.setWindowExt( m_BBox.width(), m_BBox.height() );
00772 
00773     for (int index = 0; index < m_commands.count(); ++index)
00774     {
00775         cmd = m_commands.at(index);
00776         idx = cmd->funcIndex;
00777         ( this->*metaFuncTab[ idx ].method )( elements, cmd->numParam, cmd->params );
00778 
00779         if ( WMFIMPORT_DEBUG )  {
00780             QString str = "", param;
00781             if ( metaFuncTab[ idx ].name == NULL ) {
00782                 str += "UNKNOWN ";
00783             }
00784             if ( metaFuncTab[ idx ].method == &WMFImport::noop ) {
00785                 str += "UNIMPLEMENTED ";
00786             }
00787             str += metaFuncTab[ idx ].name;
00788             str += " : ";
00789 
00790             for ( i=0 ; i < cmd->numParam ; i++ ) {
00791                 param.setNum( cmd->params[ i ] );
00792                 str += param;
00793                 str += " ";
00794             }
00795             cerr << str.toAscii().data() << endl;
00796         }
00797     }
00798     return elements;
00799 }
00800 
00801 void WMFImport::finishCmdParsing( PageItem* item )
00802 {
00803     QMatrix gcm  = m_context.worldMatrix();
00804     double coeff1 = sqrt(gcm.m11() * gcm.m11() + gcm.m12() * gcm.m12());
00805     double coeff2 = sqrt(gcm.m21() * gcm.m21() + gcm.m22() * gcm.m22());
00806     if( item->asImageFrame() )
00807     {
00808         item->moveBy(gcm.dx(), gcm.dy());
00809         item->setWidthHeight(item->width() * gcm.m11(), item->height() * gcm.m22());
00810         item->setLineWidth(qMax(item->lineWidth() * (coeff1 + coeff2) / 2.0, 0.25));
00811         if (item->PicAvail)
00812             item->setImageXYScale(item->width() / item->pixm.width(), item->height() / item->pixm.height());
00813     }
00814     else if( item->asTextFrame() )
00815     {
00816         item->setLineWidth(qMax(item->lineWidth() * (coeff1 + coeff2) / 2.0, 0.25));
00817     }
00818     else
00819     {
00820         item->ClipEdited = true;
00821         item->FrameType = 3;
00822         item->PoLine.map(gcm);
00823         item->setLineWidth(qMax(item->lineWidth() * (coeff1 + coeff2) / 2.0, 0.25));
00824         FPoint wh = getMaxClipF(&item->PoLine);
00825         item->setWidthHeight(wh.x(), wh.y());
00826         m_Doc->AdjustItemSize(item);
00827     }
00828     item->setRedrawBounding();
00829     item->OwnPage   = m_Doc->OnPage(item);
00830     item->PLineEnd  = m_context.pen().capStyle();
00831     item->PLineJoin = m_context.pen().joinStyle();
00832     item->setTextFlowMode(PageItem::TextFlowDisabled);
00833     //item->DashOffset = gc->dashOffset;
00834     //item->DashValues = gc->dashArray;
00835 }
00836 
00837 void WMFImport::setWindowOrg( QList<PageItem*>& /*items*/, long, short* params )
00838 {
00839     m_context.setWindowOrg( params[ 1 ], params[ 0 ] );
00840 }
00841 
00842 void WMFImport::setWindowExt( QList<PageItem*>& /*items*/, long, short* params )
00843 {
00844     m_context.setWindowExt( params[ 1 ], params[ 0 ] );
00845 }
00846 
00847 void WMFImport::lineTo( QList<PageItem*>& items, long, short* params )
00848 {
00849     double BaseX = m_Doc->currentPage()->xOffset();
00850     double BaseY = m_Doc->currentPage()->yOffset();
00851     QPoint currentPos = m_context.position();
00852     bool   doStroke = (m_context.pen().style() != Qt::NoPen);
00853     if (doStroke)
00854     {
00855         double