/* This file is part of the KDE Project Copyright (C) 2000 Klaas Freitag This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "previewer.h" #include "img_canvas.h" #include "sizeindicator.h" #include "devselector.h" /* for definition of config key :( */ #include "kscandevice.h" #include #include #include #include #include #include #include #define ID_CUSTOM 0 #define ID_A4 1 #define ID_A5 2 #define ID_A6 3 #define ID_9_13 4 #define ID_10_15 5 #define ID_LETTER 6 /** Config tags for autoselection **/ #define CFG_AUTOSEL_DO "doAutoselection" /* do it or not */ #define CFG_AUTOSEL_THRESH "autoselThreshold" /* threshold */ #define CFG_AUTOSEL_DUSTSIZE "autoselDustsize" /* dust size */ /* tag if a scan of the empty scanner results in black or white image */ #define CFG_SCANNER_EMPTY_BG "scannerBackgroundWhite" /* Defaultvalues for the threshold for the autodetection */ #define DEF_THRESH_BLACK "45" #define DEF_THRESH_WHITE "240" /* Items for the combobox to set the color of an empty scan */ #define BG_ITEM_BLACK 0 #define BG_ITEM_WHITE 1 class Previewer::PreviewerPrivate { public: PreviewerPrivate(): m_doAutoSelection(false), m_autoSelThresh(0), m_dustsize(5), m_bgIsWhite(false), m_sliderThresh(0), m_sliderDust(0), m_cbAutoSel(0), m_cbBackground(0), m_autoSelGroup(0), m_scanner(0) { } bool m_doAutoSelection; /* switch auto-selection on and off */ int m_autoSelThresh; /* threshold for auto selection */ int m_dustsize; /* dustsize for auto selection */ bool m_bgIsWhite; /* indicates if a scan without paper * results in black or white */ TQSlider *m_sliderThresh; TQSlider *m_sliderDust; TQCheckBox *m_cbAutoSel; TQComboBox *m_cbBackground; TQGroupBox *m_autoSelGroup; KScanDevice *m_scanner; TQMemArray m_heightSum; TQMemArray m_widthSum; }; Previewer::Previewer(TQWidget *parent, const char *name ) : TQWidget(parent,name) { d = new PreviewerPrivate(); // beautification to look like the left scanparams widget in the dialog TQHBoxLayout *htop = new TQHBoxLayout( this ); TQFrame *frame = new TQFrame( this ); frame->setFrameStyle( TQFrame::Panel | TQFrame::Raised ); frame->setLineWidth( 1 ); htop->addWidget( frame ); TQVBoxLayout *top = new TQVBoxLayout( frame, KDialog::marginHint(), KDialog::spacingHint() ); layout = new TQHBoxLayout( KDialog::spacingHint() ); top->addLayout( layout, 9 ); TQVBoxLayout *left = new TQVBoxLayout( KDialog::spacingHint() ); layout->addLayout( left, 2 ); /* Load autoselection values from Config file */ KConfig *cfg = KGlobal::config(); cfg->setGroup( GROUP_STARTUP ); /* Units etc. TODO: get from Config */ sizeUnit = KRuler::Millimetres; displayUnit = sizeUnit; d->m_autoSelThresh = 240; overallHeight = 295; /* Default DIN A4 */ overallWidth = 210; kdDebug(29000) << "Previewer: got Overallsize: " << overallWidth << " x " << overallHeight << endl; img_canvas = new ImageCanvas( frame ); img_canvas->setDefaultScaleKind( ImageCanvas::DYNAMIC ); img_canvas->enableContextMenu(true); img_canvas->repaint(); layout->addWidget( img_canvas, 6 ); /* Actions for the previewer zoom */ KAction *act; act = new KAction(i18n("Scale to W&idth"), "scaletowidth", CTRL+Key_I, TQT_TQOBJECT(this), TQT_SLOT( slScaleToWidth()), TQT_TQOBJECT(this), "preview_scaletowidth" ); act->plug( img_canvas->contextMenu()); act = new KAction(i18n("Scale to &Height"), "scaletoheight", CTRL+Key_H, TQT_TQOBJECT(this), TQT_SLOT( slScaleToHeight()), TQT_TQOBJECT(this), "preview_scaletoheight" ); act->plug( img_canvas->contextMenu()); /*Signals: Control the custom-field and show size of selection */ connect( img_canvas, TQT_SIGNAL(newRect()), this, TQT_SLOT(slCustomChange())); connect( img_canvas, TQT_SIGNAL(newRect(TQRect)), this, TQT_SLOT(slNewDimen(TQRect))); /* Stuff for the preview-Notification */ left->addWidget( new TQLabel( i18n("Preview"), frame ), 1); // Create a button group to contain buttons for Portrait/Landscape bgroup = new TQVButtonGroup( i18n("Scan Size"), frame ); // ----- pre_format_combo = new TQComboBox( frame, "PREVIEWFORMATCOMBO" ); pre_format_combo->insertItem( i18n( "Custom" ), ID_CUSTOM); pre_format_combo->insertItem( i18n( "DIN A4" ), ID_A4); pre_format_combo->insertItem( i18n( "DIN A5" ), ID_A5); pre_format_combo->insertItem( i18n( "DIN A6" ), ID_A6); pre_format_combo->insertItem( i18n( "9x13 cm" ), ID_9_13 ); pre_format_combo->insertItem( i18n( "10x15 cm" ), ID_10_15 ); pre_format_combo->insertItem( i18n( "Letter" ), ID_LETTER); connect( pre_format_combo, TQT_SIGNAL(activated (int)), this, TQT_SLOT( slFormatChange(int))); left->addWidget( pre_format_combo, 1 ); /** Potrait- and Landscape Selector **/ TQFontMetrics fm = bgroup->fontMetrics(); int w = fm.width( (const TQString)i18n(" Landscape " ) ); int h = fm.height( ); rb1 = new TQRadioButton( i18n("&Landscape"), bgroup ); landscape_id = bgroup->id( rb1 ); rb2 = new TQRadioButton( i18n("P&ortrait"), bgroup ); portrait_id = bgroup->id( rb2 ); bgroup->setButton( portrait_id ); connect(bgroup, TQT_SIGNAL(clicked(int)), this, TQT_SLOT(slOrientChange(int))); int rblen = 5+w+12; // 12 for the button? rb1->setGeometry( 5, 6, rblen, h ); rb2->setGeometry( 5, 1+h/2+h, rblen, h ); left->addWidget( bgroup, 2 ); /** Autoselection Box **/ d->m_autoSelGroup = new TQGroupBox( 1,Qt::Horizontal, i18n("Auto-Selection"), frame); TQHBox *hbox = new TQHBox(d->m_autoSelGroup); d->m_cbAutoSel = new TQCheckBox( i18n("Active on"), hbox ); TQToolTip::add( d->m_cbAutoSel, i18n("Check here if you want autodetection\n" "of the document on the preview.")); /* combobox to select if black or white background */ d->m_cbBackground = new TQComboBox( hbox ); d->m_cbBackground->insertItem(i18n("Black"), BG_ITEM_BLACK ); d->m_cbBackground->insertItem(i18n("White"), BG_ITEM_WHITE ); connect( d->m_cbBackground, TQT_SIGNAL(activated(int) ), this, TQT_SLOT( slScanBackgroundChanged( int ))); TQToolTip::add( d->m_cbBackground, i18n("Select whether a scan of the empty\n" "scanner glass results in a\n" "black or a white image.")); connect( d->m_cbAutoSel, TQT_SIGNAL(toggled(bool) ), TQT_SLOT(slAutoSelToggled(bool))); (void) new TQLabel( i18n("scanner background"), d->m_autoSelGroup ); TQLabel *l1= new TQLabel( i18n("Thresh&old:"), d->m_autoSelGroup ); d->m_sliderThresh = new TQSlider( 0, 254, 10, d->m_autoSelThresh, Qt::Horizontal, d->m_autoSelGroup ); connect( d->m_sliderThresh, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slSetAutoSelThresh(int))); TQToolTip::add( d->m_sliderThresh, i18n("Threshold for autodetection.\n" "All pixels higher (on black background)\n" "or smaller (on white background)\n" "than this are considered to be part of the image.")); l1->setBuddy(d->m_sliderThresh); #if 0 /** Dustsize-Slider: No deep impact on result **/ (void) new TQLabel( i18n("Dust size:"), grBox ); d->m_sliderDust = new TQSlider( 0, 50, 5, d->m_dustsize, Qt::Horizontal, grBox ); connect( d->m_sliderDust, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slSetAutoSelDustsize(int))); #endif /* disable Autoselbox as long as no scanner is connected */ d->m_autoSelGroup->setEnabled(false); left->addWidget(d->m_autoSelGroup); /* Labels for the dimension */ TQGroupBox *gbox = new TQGroupBox( 1,Qt::Horizontal, i18n("Selection"), frame, "GROUPBOX" ); TQLabel *l2 = new TQLabel( i18n("width - mm" ), gbox ); TQLabel *l3 = new TQLabel( i18n("height - mm" ), gbox ); connect( this, TQT_SIGNAL(setScanWidth(const TQString&)), l2, TQT_SLOT(setText(const TQString&))); connect( this, TQT_SIGNAL(setScanHeight(const TQString&)), l3, TQT_SLOT(setText(const TQString&))); /* size indicator */ TQHBox *hb = new TQHBox( gbox ); (void) new TQLabel( i18n( "Size:"), hb ); SizeIndicator *indi = new SizeIndicator( hb ); TQToolTip::add( indi, i18n( "This size field shows how large the uncompressed image will be.\n" "It tries to warn you, if you try to produce huge images by \n" "changing its background color." )); indi->setText( i18n("-") ); connect( this, TQT_SIGNAL( setSelectionSize(long)), indi, TQT_SLOT( setSizeInByte (long)) ); left->addWidget( gbox, 1 ); left->addStretch( 6 ); top->activate(); /* Preset custom Cutting */ pre_format_combo->setCurrentItem( ID_CUSTOM ); slFormatChange( ID_CUSTOM); scanResX = -1; scanResY = -1; pix_per_byte = 1; selectionWidthMm = 0.0; selectionHeightMm = 0.0; recalcFileSize(); } Previewer::~Previewer() { delete d; } bool Previewer::setPreviewImage( const TQImage &image ) { if ( image.isNull() ) return false; m_previewImage = image; img_canvas->newImage( &m_previewImage ); return true; } TQString Previewer::galleryRoot() { TQString dir = (KGlobal::dirs())->saveLocation( "data", "ScanImages", true ); if( !dir.endsWith("/") ) dir += "/"; return( dir ); } void Previewer::newImage( TQImage *ni ) { /* image canvas does not copy the image, so we hold a copy here */ m_previewImage = *ni; /* clear the auto detection arrays */ d->m_heightSum.resize( 0 ); d->m_widthSum.resize( 0 ); img_canvas->newImage( &m_previewImage ); findSelection( ); } void Previewer::setScanSize( int w, int h, KRuler::MetricStyle unit ) { overallWidth = w; overallHeight = h; sizeUnit = unit; } void Previewer::slSetDisplayUnit( KRuler::MetricStyle unit ) { displayUnit = unit; } void Previewer::slOrientChange( int id ) { (void) id; /* Gets either portrait or landscape-id */ /* Just read the format-selection and call slFormatChange */ slFormatChange( pre_format_combo->currentItem() ); } /** Slot called whenever the format selection combo changes. **/ void Previewer::slFormatChange( int id ) { TQPoint p(0,0); bool lands_allowed; bool portr_allowed; bool setSelection = true; int s_long = 0; int s_short= 0; isCustom = false; switch( id ) { case ID_LETTER: s_long = 294; s_short = 210; lands_allowed = false; portr_allowed = true; break; case ID_CUSTOM: lands_allowed = false; portr_allowed = false; setSelection = false; isCustom = true; break; case ID_A4: s_long = 297; s_short = 210; lands_allowed = false; portr_allowed = true; break; case ID_A5: s_long = 210; s_short = 148; lands_allowed = true; portr_allowed = true; break; case ID_A6: s_long = 148; s_short = 105; lands_allowed = true; portr_allowed = true; break; case ID_9_13: s_long = 130; s_short = 90; lands_allowed = true; portr_allowed = true; break; case ID_10_15: s_long = 150; s_short = 100; lands_allowed = true; portr_allowed = true; break; default: lands_allowed = true; portr_allowed = true; setSelection = false; break; } rb1->setEnabled( lands_allowed ); rb2->setEnabled( portr_allowed ); int format_id = bgroup->id( bgroup->selected() ); if( !lands_allowed && format_id == landscape_id ) { bgroup->setButton( portrait_id ); format_id = portrait_id; } /* Convert the new dimension to a new TQRect and call slot in canvas */ if( setSelection ) { TQRect newrect; newrect.setRect( 0,0, p.y(), p.x() ); if( format_id == portrait_id ) { /* Portrait Mode */ p = calcPercent( s_short, s_long ); kdDebug(29000) << "Now is portrait-mode" << endl; } else { /* Landscape-Mode */ p = calcPercent( s_long, s_short ); } newrect.setWidth( p.x() ); newrect.setHeight( p.y() ); img_canvas->newRectSlot( newrect ); } } /* This is called when the user fiddles around in the image. * This makes the selection custom-sized immediately. */ void Previewer::slCustomChange( void ) { if( isCustom )return; pre_format_combo->setCurrentItem(ID_CUSTOM); slFormatChange( ID_CUSTOM ); } void Previewer::slNewScanResolutions( int x, int y ) { kdDebug(29000) << "got new Scan Resolutions: " << x << "|" << y << endl; scanResX = x; scanResY = y; recalcFileSize(); } /* This slot is called with the new dimension for the selection * in values between 0..1000. It emits signals, that redraw the * size labels. */ void Previewer::slNewDimen(TQRect r) { if( r.height() > 0) selectionWidthMm = (overallWidth / 1000 * r.width()); if( r.width() > 0) selectionHeightMm = (overallHeight / 1000 * r.height()); TQString s; s = i18n("width %1 mm").arg( int(selectionWidthMm)); emit(setScanWidth(s)); kdDebug(29000) << "Setting new Dimension " << s << endl; s = i18n("height %1 mm").arg(int(selectionHeightMm)); emit(setScanHeight(s)); recalcFileSize( ); } void Previewer::recalcFileSize( void ) { /* Calculate file size */ long size_in_byte = 0; if( scanResY > -1 && scanResX > -1 ) { double w_inch = ((double) selectionWidthMm) / 25.4; double h_inch = ((double) selectionHeightMm) / 25.4; int pix_w = int( w_inch * double( scanResX )); int pix_h = int( h_inch * double( scanResY )); size_in_byte = pix_w * pix_h / pix_per_byte; } emit( setSelectionSize( size_in_byte )); } TQPoint Previewer::calcPercent( int w_mm, int h_mm ) { TQPoint p(0,0); if( overallWidth < 1.0 || overallHeight < 1.0 ) return( p ); if( sizeUnit == KRuler::Millimetres ) { p.setX( static_cast(1000.0*w_mm / overallWidth) ); p.setY( static_cast(1000.0*h_mm / overallHeight) ); } else { kdDebug(29000) << "ERROR: Only mm supported yet !" << endl; } return( p ); } void Previewer::slScaleToWidth() { if( img_canvas ) { img_canvas->handle_popup( ImageCanvas::ID_FIT_WIDTH ); } } void Previewer::slScaleToHeight() { if( img_canvas ) { img_canvas->handle_popup( ImageCanvas::ID_FIT_HEIGHT); } } void Previewer::slConnectScanner( KScanDevice *scan ) { kdDebug(29000) << "Connecting scan device!" << endl; d->m_scanner = scan; if( scan ) { /* Enable the by-default disabled autoselection group */ d->m_autoSelGroup->setEnabled(true); TQString h; h = scan->getConfig( CFG_AUTOSEL_DO, TQString("unknown") ); if( h == TQString("on") ) d->m_cbAutoSel->setChecked(true); else d->m_cbAutoSel->setChecked(false); TQString isWhite = d->m_scanner->getConfig( CFG_SCANNER_EMPTY_BG, "unknown" ); h = scan->getConfig( CFG_AUTOSEL_DUSTSIZE, TQString("5") ); d->m_dustsize = h.toInt(); TQString thresh = DEF_THRESH_BLACK; /* for black */ if( isWhite.lower() == "yes" ) thresh = DEF_THRESH_WHITE; h = scan->getConfig( CFG_AUTOSEL_THRESH, thresh ); d->m_sliderThresh->setValue( h.toInt() ); } } void Previewer::slSetScannerBgIsWhite( bool b ) { d->m_bgIsWhite = b; if( d->m_scanner ) { if( b ) // The background _is_ white { d->m_cbBackground->setCurrentItem( BG_ITEM_WHITE ); } else { d->m_cbBackground->setCurrentItem( BG_ITEM_BLACK ); } d->m_scanner->slStoreConfig( CFG_SCANNER_EMPTY_BG, b ? TQString("Yes") : TQString("No")); } } /** * reads the scanner dependant config file through the m_scanner pointer. * If a value for the scanner is not yet known, the function starts up a * popup and asks the user. The result is stored. */ void Previewer::checkForScannerBg() { if( d->m_scanner ) /* Is the scan device already known? */ { TQString isWhite = d->m_scanner->getConfig( CFG_SCANNER_EMPTY_BG, "unknown" ); bool goWhite = false; if( isWhite == "unknown" ) { /* not yet known, should ask the user. */ kdDebug(29000) << "Dont know the scanner background yet!" << endl; goWhite = ( KMessageBox::questionYesNo( this, i18n("The autodetection of images on the preview depends on the background color of the preview image (Think of a preview of an empty scanner).\nPlease select whether the background of the preview image is black or white"), i18n("Image Autodetection"), i18n("White"), i18n("Black") ) == KMessageBox::Yes ); kdDebug(29000) << "User said " << isWhite << endl; } else { if( isWhite.lower() == "yes" ) goWhite = true; } /* remember value */ slSetScannerBgIsWhite( goWhite ); } } void Previewer::slScanBackgroundChanged( int indx ) { slSetScannerBgIsWhite( indx == BG_ITEM_WHITE ); } void Previewer::slAutoSelToggled(bool isOn ) { if( isOn ) checkForScannerBg(); if( d->m_cbAutoSel ) { TQRect r = img_canvas->sel(); kdDebug(29000) << "The rect is " << r.width() << " x " << r.height() << endl; d->m_doAutoSelection = isOn; /* Store configuration */ if( d->m_scanner ) { d->m_scanner->slStoreConfig( CFG_AUTOSEL_DO, isOn ? "on" : "off" ); } if( isOn && r.width() < 2 && r.height() < 2) /* There is no selection yet */ { /* if there is already an image, check, if the bg-color is set already */ if( img_canvas->rootImage() ) { kdDebug(29000) << "No selection -> try to find one!" << endl; findSelection(); } } } if( d->m_sliderThresh ) d->m_sliderThresh->setEnabled(isOn); if( d->m_sliderDust ) d->m_sliderDust->setEnabled(isOn); if( d->m_cbBackground ) d->m_cbBackground->setEnabled(isOn); } void Previewer::slSetAutoSelThresh(int t) { d->m_autoSelThresh = t; kdDebug(29000) << "Setting threshold to " << t << endl; if( d->m_scanner ) d->m_scanner->slStoreConfig( CFG_AUTOSEL_THRESH, TQString::number(t) ); findSelection(); } void Previewer::slSetAutoSelDustsize(int dSize) { d->m_dustsize = dSize; kdDebug(29000) << "Setting dustsize to " << dSize << endl; findSelection(); } /** * This method tries to find a selection on the preview image automatically. * It uses the image of the preview image canvas, the previewer global * threshold setting and a dustsize. **/ void Previewer::findSelection( ) { kdDebug(29000) << "Searching Selection" << endl; kdDebug(29000) << "Threshold: " << d->m_autoSelThresh << endl; kdDebug(29000) << "dustsize: " << d->m_dustsize << endl; kdDebug(29000) << "isWhite: " << d->m_bgIsWhite << endl; if( ! d->m_doAutoSelection ) return; int line; int x; const TQImage *img = img_canvas->rootImage(); if( ! img ) return; long iWidth = img->width(); long iHeight = img->height(); TQMemArray heightSum; TQMemArray widthSum; kdDebug(29000)<< "Preview size is " << iWidth << "x" << iHeight << endl; if( (d->m_heightSum).size() == 0 && (iHeight>0) ) { kdDebug(29000) << "Starting to fill Array " << endl; TQMemArray heightSum(iHeight); TQMemArray widthSum(iWidth); heightSum.fill(0); widthSum.fill(0); kdDebug(29000) << "filled Array with zero " << endl; for( line = 0; line < iHeight; line++ ) { for( x = 0; x < iWidth; x++ ) { int gray = tqGray( img->pixel( x, line )); // kdDebug(29000) << "Gray-Value at line " << gray << endl; Q_ASSERT( line < iHeight ); Q_ASSERT( x < iWidth ); int hsum = heightSum.at(line); int wsum = widthSum.at(x); heightSum[line] = hsum+gray; widthSum [x] = wsum+gray; } heightSum[line] = heightSum[line]/iWidth; } /* Divide by amount of pixels */ kdDebug(29000) << "Resizing now" << endl; for( x = 0; x < iWidth; x++ ) widthSum[x] = widthSum[x]/iHeight; kdDebug(29000) << "Filled Arrays successfully" << endl; d->m_widthSum = widthSum; d->m_heightSum = heightSum; } /* Now try to find values in arrays that have grayAdds higher or lower * than threshold */ #if 0 /* debug output */ { TQFile fi( "/tmp/thheight.dat"); if( fi.open( IO_ReadWrite ) ) { TQTextStream str( &fi ); str << "# height ##################" << endl; for( x = 0; x < iHeight; x++ ) str << x << '\t' << d->m_heightSum[x] << endl; fi.close(); } } TQFile fi1( "/tmp/thwidth.dat"); if( fi1.open( IO_ReadWrite )) { TQTextStream str( &fi1 ); str << "# width ##################" << endl; str << "# " << iWidth << " points" << endl; for( x = 0; x < iWidth; x++ ) str << x << '\t' << d->m_widthSum[x] << endl; fi1.close(); } #endif int start = 0; int end = 0; TQRect r; /** scale to 0..1000 range **/ start = 0; end = 0; imagePiece( d->m_heightSum, start, end ); // , d->m_threshold, d->m_dustsize, false ); r.setTop( 1000*start/iHeight ); r.setBottom( 1000*end/iHeight); // r.setTop( start ); // r.setBottom( end ); start = 0; end = 0; imagePiece( d->m_widthSum, start, end ); // , d->m_threshold, d->m_dustsize, false ); r.setLeft( 1000*start/iWidth ); r.setRight( 1000*end/iWidth ); // r.setLeft( start ); // r.setRight( end ); kdDebug(29000) << " -- Autodetection -- " << endl; kdDebug(29000) << "Area top " << r.top() << endl; kdDebug(29000) << "Area left" << r.left() << endl; kdDebug(29000) << "Area bottom " << r.bottom() << endl; kdDebug(29000) << "Area right " << r.right() << endl; kdDebug(29000) << "Area width " << r.width() << endl; kdDebug(29000) << "Area height " << r.height() << endl; img_canvas->newRectSlot( r ); slCustomChange(); } /* * returns an Array containing the */ bool Previewer::imagePiece( TQMemArray src, int& start, int& end ) { for( uint x = 0; x < src.size(); x++ ) { if( !d->m_bgIsWhite ) { /* pixelvalue needs to be higher than threshold, white background */ if( src[x] > d->m_autoSelThresh ) { /* Ok this pixel could be the start */ int iStart = x; int iEnd = x; x++; while( x < src.size() && src[x] > d->m_autoSelThresh ) { x++; } iEnd = x; int delta = iEnd-iStart; if( delta > d->m_dustsize && end-start < delta ) { start = iStart; end = iEnd; } } } else { /* pixelvalue needs to be lower than threshold, black background */ if( src[x] < d->m_autoSelThresh ) { int iStart = x; int iEnd = x; x++; while( x < src.size() && src[x] < d->m_autoSelThresh ) { x++; } iEnd = x; int delta = iEnd-iStart; if( delta > d->m_dustsize && end-start < delta ) { start = iStart; end = iEnd; } } } } return (end-start)>0; } #include "previewer.moc"