You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kile/src/kile/includegraphicsdialog.cpp

532 lines
16 KiB

/***************************************************************************
date : Dec 06 2005
version : 0.24
copyright : (C) 2004-2005 by Holger Danielsson, 2004 Jeroen Wijnhout
email : holger.danielsson@t-online.de
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "includegraphicsdialog.h"
#include <tqregexp.h>
#include <tqfileinfo.h>
#include <tqgroupbox.h>
#include <tqvgroupbox.h>
#include <tqlayout.h>
#include <tqpixmap.h>
#include <tqcheckbox.h>
#include <tqlabel.h>
#include <tdelocale.h>
#include <tdefiledialog.h>
#include <kiconloader.h>
#include <tdemessagebox.h>
#include "kiledebug.h"
#include <kpushbutton.h>
#include <kprocess.h>
#include <klineedit.h>
#include "kileconfig.h"
#include "kileinfo.h"
#include "kileedit.h"
namespace KileDialog
{
IncludeGraphics::IncludeGraphics(TQWidget *parent, const TQString &startdir, KileInfo *ki) :
KDialogBase( Plain, i18n("Include Graphics"), Ok | Cancel, Ok, parent, 0, true, true),
m_startdir(startdir),
m_width(0),
m_height(0),
m_ki(ki),
m_proc(0)
{
// Layout
TQVBoxLayout *vbox = new TQVBoxLayout(plainPage(), 6,6 );
// first groupbox: choose picture
TQVGroupBox* group= new TQVGroupBox(i18n("File"), plainPage());
TQWidget *widget = new TQWidget(group);
TQGridLayout *grid = new TQGridLayout( widget, 4,3, 6,6, "");
grid->addRowSpacing( 0, fontMetrics().lineSpacing() );
grid->addColSpacing( 0, fontMetrics().lineSpacing() );
grid->setColStretch(1,1);
// line 1: TQLabel
TQLabel *label1 = new TQLabel(i18n("Picture:"), widget);
grid->addWidget( label1, 0,0 );
// line 1: KLineEdit
edit_file = new KLineEdit("",widget);
edit_file->setMinimumWidth(300);
grid->addWidget( edit_file, 0,1 );
// line 1: Choose-Box
KPushButton *pb_choose = new KPushButton("", widget, "filechooser_button" );
pb_choose->setPixmap( SmallIcon("document-open") );
pb_choose->setFixedWidth(pb_choose->sizeHint().width()); // set width
grid->addRowSpacing( 0, pb_choose->sizeHint().height()+5 ); // update height of line
grid->addWidget(pb_choose,0,2);
// line 2: some (more or less useful) information
TQLabel *label2 = new TQLabel(i18n("Info:"), widget);
infolabel = new TQLabel("---", widget);
grid->addWidget( label2, 1,0 );
grid->addWidget( infolabel, 1,1 );
// line 3: some output options
TQLabel *label3 = new TQLabel(i18n("Output:"), widget);
TQWidget *cb_widget = new TQWidget(widget);
TQGridLayout *cb_grid = new TQGridLayout( cb_widget, 1,2, 0,0,"");
cb_center = new TQCheckBox(i18n("Center picture"),cb_widget);
cb_pdftex = new TQCheckBox(i18n("pdftex/pdflatex"),cb_widget);
cb_grid->addWidget(cb_center,0,0);
cb_grid->addWidget(cb_pdftex,0,1);
grid->addWidget( label3, 2,0 );
grid->addWidget( cb_widget, 2,1 );
// line 4: graphics path
TQLabel *label5 = new TQLabel(i18n("Path:"), widget);
cb_graphicspath = new TQCheckBox(i18n("Use \\graphicspath command of LaTeX"),widget);
grid->addWidget( label5, 3,0 );
grid->addWidget( cb_graphicspath, 3,1 );
// second groupbox: options
TQVGroupBox* gb_opt= new TQVGroupBox(i18n("Options"), plainPage());
TQWidget *widget_opt = new TQWidget(gb_opt);
TQGridLayout *grid_opt = new TQGridLayout( widget_opt, 2,4, 6,6, "");
TQLabel *label7 = new TQLabel(i18n("Width:"), widget_opt);
TQLabel *label8 = new TQLabel(i18n("Height:"),widget_opt);
TQLabel *label9 = new TQLabel(i18n("Angle:"), widget_opt);
TQLabel *label10= new TQLabel(i18n("Bounding box:"), widget_opt);
edit_width = new KLineEdit("",widget_opt);
edit_height = new KLineEdit("",widget_opt);
edit_angle = new KLineEdit("",widget_opt);
edit_bb = new KLineEdit("",widget_opt);
grid_opt->addWidget( label7, 0,0, TQt::AlignRight );
grid_opt->addWidget( edit_width, 0,1 );
grid_opt->addWidget( label9, 0,2, TQt::AlignRight );
grid_opt->addWidget( edit_angle, 0,3 );
grid_opt->addWidget( label8, 1,0, TQt::AlignRight );
grid_opt->addWidget( edit_height, 1,1 );
grid_opt->addWidget( label10, 1,2, TQt::AlignRight );
grid_opt->addWidget( edit_bb, 1,3 );
// third groupbox: figure environment
TQGroupBox *gb_fig= new TQGroupBox(2,TQt::Horizontal,i18n("Figure Environment"), plainPage());
TQWidget *widget_fig = new TQWidget(gb_fig);
TQGridLayout *grid_fig = new TQGridLayout( widget_fig, 3,2, 6,6, "");
TQLabel *label4 = new TQLabel(i18n("Figure:"), widget_fig);
lb_label = new TQLabel(i18n("Label:"), widget_fig);
lb_caption = new TQLabel(i18n("Caption:"), widget_fig);
cb_figure = new TQCheckBox(i18n("Use figure environment"),widget_fig);
edit_label = new KLineEdit("fig:",widget_fig);
edit_caption = new KLineEdit("",widget_fig);
grid_fig->addWidget( label4,0,0);
grid_fig->addWidget( cb_figure, 0,1);
grid_fig->addWidget( lb_label,1,0);
grid_fig->addWidget( edit_label, 1,1);
grid_fig->addWidget( lb_caption,2,0);
grid_fig->addWidget( edit_caption, 2,1);
// add to layout
vbox->addWidget(group);
vbox->addWidget(gb_opt);
vbox->addWidget(gb_fig);
vbox->addStretch();
// read configuration
readConfig();
updateFigure();
// connect
connect( pb_choose, TQ_SIGNAL( clicked() ), this, TQ_SLOT( chooseFile() ) );
connect( cb_figure, TQ_SIGNAL(clicked()), this, TQ_SLOT(updateFigure() ) );
setFocusProxy( edit_file );
}
IncludeGraphics::~IncludeGraphics()
{
delete m_proc;
}
////////////////////////////// configuration data //////////////////////////////
void IncludeGraphics::readConfig()
{
cb_center->setChecked( KileConfig::igCenter() );
cb_pdftex->setChecked( KileConfig::igPdftex() );
cb_graphicspath->setChecked( KileConfig::igGraphicspath() );
cb_figure->setChecked( KileConfig::igFigure() );
m_imagemagick = KileConfig::imagemagick();
m_boundingbox = KileConfig::boundingbox();
m_defaultresolution = KileConfig::resolution();
}
void IncludeGraphics::writeConfig()
{
KileConfig::setIgCenter( cb_center->isChecked() );
KileConfig::setIgPdftex( cb_pdftex->isChecked() );
KileConfig::setIgGraphicspath( cb_graphicspath->isChecked() );
KileConfig::setIgFigure( cb_figure->isChecked() );
}
////////////////////////////// update figure environment //////////////////////////////
void IncludeGraphics::updateFigure()
{
bool state = cb_figure->isChecked();
lb_label->setEnabled(state);
lb_caption->setEnabled(state);
edit_label->setEnabled(state);
edit_caption->setEnabled(state);
}
////////////////////////////// determine the whole tag //////////////////////////////
TQString IncludeGraphics::getTemplate()
{
TQString s;
// state of figure and center checkbox
bool figure = cb_figure->isChecked();
bool center = cb_center->isChecked();
TQString indent = ( figure || center ) ? m_ki->editorExtension()->autoIndentEnvironment() : TQString();
// add start of figure environment ?
if ( figure )
s += "\\begin{figure}\n";
// add start of center environment ?
if ( center )
{
if ( figure )
s += indent + "\\centering\n";
else
s += "\\begin{center}\n";
}
// add includegraphics command
s += indent + "\\includegraphics";
// add some options
TQString options = getOptions();
if ( !options.isEmpty() )
s += '[' + options + ']';
// add name of picture
// either take the filename or try to take the relative part of the name
TQString filename = ( cb_graphicspath->isChecked() )
? TQFileInfo(edit_file->text()).fileName()
: m_ki->relativePath(TQFileInfo(m_ki->getCompileName()).dirPath(), edit_file->text());
s += '{' + filename + "}\n";
// add some comments (depending of given resolution, this may be wrong!)
TQString info = getInfo();
if (info.length() > 0)
s += indent + info + '\n';
// close center environment ?
if ( center && !figure )
s += "\\end{center}\n";
// close figure environment ?
if ( figure )
{
TQString caption = edit_caption->text().stripWhiteSpace();
if ( !caption.isEmpty() )
s += indent + "\\caption{" + caption + "}\n";
TQString label = edit_label->text().stripWhiteSpace();
if ( !label.isEmpty() && label!="fig:" )
s += indent + "\\label{" + label + "}\n";
s += "\\end{figure}\n";
}
return s;
}
TQString IncludeGraphics::getFilename()
{
return edit_file->text();
}
////////////////////////////// some calculations //////////////////////////////
TQString IncludeGraphics::getOptions()
{
TQString s = "";
if ( ! edit_width->text().isEmpty() )
s += ",width=" + edit_width->text();
if ( ! edit_height->text().isEmpty() )
s += ",height=" + edit_height->text();
if ( ! edit_angle->text().isEmpty() )
s += ",angle=" + edit_angle->text();
// Only dvips needs the bounding box, not pdftex/pdflatex.
// But it will be always inserted as a comment.
if ( !edit_bb->text().isEmpty() && !cb_pdftex->isChecked() )
s += ",bb=" + edit_bb->text();
if ( s.left(1) == "," )
return s.right(s.length()-1);
else
return s;
}
////////////////////////////// graphics info //////////////////////////////
TQString IncludeGraphics::getInfo()
{
TQString wcm,hcm,dpi;
int wpx=0,hpx=0;
bool ok = getPictureSize(wpx,hpx,dpi,wcm,hcm);
if ( ! ok )
return "";
else
{
TQFileInfo fi( edit_file->text() );
return "% " + fi.baseName() + '.' + fi.extension(true)
+ TQString(": %1x%2 pixel").arg(wpx).arg(hpx)
+ ", " + dpi + "dpi"
+ ", " + wcm + 'x' + hcm + " cm"
+ ", bb=" + edit_bb->text();
}
}
void IncludeGraphics::setInfo()
{
TQString text;
TQString wcm,hcm,dpi;
int wpx,hpx;
if ( !edit_file->text().isEmpty() && getPictureSize(wpx,hpx,dpi,wcm,hcm) )
{
text = TQString("%1x%2 pixel").arg(wpx).arg(hpx)
+ " / " + wcm + 'x' + hcm + " cm"
+ " (" + dpi + "dpi)";
}
else
text = "---";
// insert text
infolabel->setText(text);
}
bool IncludeGraphics::getPictureSize(int &wpx, int &hpx, TQString &dpi, TQString &wcm, TQString &hcm)
{
wpx = m_width;
hpx = m_height;
dpi = TQString("%1").arg((int)(m_resolution+0.5));
// convert from inch to cm
float w = (float)m_width / m_resolution * 2.54;
wcm = wcm.setNum(w,'f',2);
float h = (float)m_height / m_resolution * 2.54;
hcm = hcm.setNum(h,'f',2);
return true;
}
void IncludeGraphics::chooseFile()
{
TQString filter = ( cb_pdftex->isChecked() )
? i18n("*.png *.jpg *.pdf|Graphics\n") // dani 31.7.2004
+ "*.png|PNG Files\n"
+ "*.jpg|JPG Files\n"
+ "*.pdf|PDF Files\n"
+ "*|All Files"
: i18n("*.png *.jpg *.eps.gz *.eps|Graphics\n") // dani 31.7.2004
+ "*.png|PNG Files\n"
+ "*.jpg|JPG Files\n"
+ "*.eps.gz|Zipped EPS Files\n"
+ "*.eps|EPS Files\n"
+ "*|All Files";
TQString fn = KFileDialog::getOpenFileName( m_startdir,filter,
this,i18n("Select File") );
TQFileInfo fi(fn);
// insert the chosen file
edit_file->setText( fn );
// could we accept the picture?
if ( !fn.isEmpty() && fi.exists() && fi.isReadable() )
{
// execute the command and filter the result:
// eps|eps.gz --> %%BoundingBox: 0 0 123 456
// bitmaps --> w=123 h=456 dpi=789
TQString grep = " | grep -m1 \"^%%BoundingBox:\"";
TQString ext = TQFileInfo(fn).extension();
if ( ext == "eps" )
execute( "cat " + fn + grep);
else if ( ext == "eps.gz" )
execute( "gunzip -c " + fn + grep);
else
execute("identify -format \"w=%w h=%h dpi=%x\" \"" + fn + "\"");
}
else{
KILE_DEBUG() << "=== IncludeGraphics::error ====================" << endl;
KILE_DEBUG() << " filename: '" << fn << "'" << endl;
}
}
void IncludeGraphics::execute(const TQString &command)
{
if ( !m_boundingbox || (!m_imagemagick && command.left(8)=="identify") )
return;
if(m_proc)
delete m_proc;
m_proc = new KShellProcess("/bin/sh");
m_proc->clearArguments();
(*m_proc) << TQStringList::split(' ',command);
connect(m_proc, TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)),
this, TQ_SLOT(slotProcessOutput(TDEProcess*,char*,int)) );
connect(m_proc, TQ_SIGNAL(receivedStderr(TDEProcess*,char*,int)),
this, TQ_SLOT(slotProcessOutput(TDEProcess*,char*,int)) );
connect(m_proc, TQ_SIGNAL(processExited(TDEProcess*)),
this, TQ_SLOT(slotProcessExited(TDEProcess*)) );
m_output = "";
KILE_DEBUG() << "=== IncludeGraphics::execute ====================" << endl;
KILE_DEBUG() << " execute '" << command << "'" << endl;
m_proc->start(TDEProcess::NotifyOnExit, TDEProcess::AllOutput);
}
// get all output of identify
void IncludeGraphics::slotProcessOutput(TDEProcess*,char* buffer,int buflen)
{
m_output += TQString::fromLocal8Bit(buffer,buflen);
}
// identify was called
void IncludeGraphics::slotProcessExited(TDEProcess* proc)
{
if ( proc->normalExit() && !proc->exitStatus() ) {
KILE_DEBUG() << " result: " << m_output << endl;
// set the default resolution
m_resolution = m_defaultresolution;
// analyze the result
if ( m_output.left(14) == "%%BoundingBox:" )
{
edit_bb->setText( m_output.stripWhiteSpace().mid(15,m_output.length()-15) );
// show information
setInfo();
}
else if ( m_output.left(2) == "w=" )
{
// dani 31.7.2004
// older version of imagemagick (pre 6.0):
// - doesn't care of PixelsPerCentimeter, but always works with PixelsPerInch
// - doesn't use floating numbers as resolution
// so the bounding box has to be calculated in a different way
// this regexp will accept floating point numbers as resolution
TQRegExp reg("w=(\\d+)\\s+h=(\\d+)\\s+dpi=([0-9.]+) (.*)");
if ( reg.search(m_output) == -1 )
return;
// get bounding box and resolution
bool ok;
m_width = (int)reg.cap(1).toInt( &ok);
if (!ok) return;
m_height = (int)reg.cap(2).toInt( &ok);
if (!ok) return;
float res = (float)reg.cap(3).toFloat( &ok);
if (!ok) return;
if ( res > 0.0 )
m_resolution = res;
// look, if resolution is in PixelsPerCentimeter
if ( reg.cap(4).stripWhiteSpace() == "PixelsPerCentimeter" )
m_resolution *= 2.54;
// calc the bounding box
int bbw = (int)( (float)m_width*72.0/m_resolution + 0.5 );
int bbh = (int)( (float)m_height*72.0/m_resolution + 0.5 );
// take width and height as parameters for the bounding box
edit_bb->setText( TQString("0 0 ") + TQString("%1").arg(bbw)
+ ' '
+ TQString("%1").arg(bbh)
);
// show information
setInfo();
}
}
}
void IncludeGraphics::slotOk()
{
if ( checkParameter() ) {
writeConfig();
accept();
}
}
bool IncludeGraphics::checkParameter()
{
TQString filename = edit_file->text().stripWhiteSpace();
edit_file->setText(filename);
if ( filename.isEmpty() )
{
if ( KMessageBox::warningYesNo( this, i18n("No graphics file was given. Proceed any way?") ) == KMessageBox::No ) return false;
}
else
{
TQFileInfo fi( filename );
if ( ! fi.exists() )
{
if ( KMessageBox::warningYesNo( this, i18n("The graphics file does not exist. Proceed any way?") ) == KMessageBox::No ) return false;
}
}
return true;
}
}
#include "includegraphicsdialog.moc"