]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiGraphics.cpp
Create new graphics from within LyX choosing a sample file to copy from.
[lyx.git] / src / frontends / qt4 / GuiGraphics.cpp
index 054b9bb891cb8a76eeb332471ae948c155923422..404df3c9d1282ae43771e75a1e15d7b6d0384ad2 100644 (file)
@@ -24,7 +24,9 @@
 #include "LengthCombo.h"
 #include "Length.h"
 #include "LyXRC.h"
+#include "Format.h"
 
+#include "graphics/epstools.h"
 #include "graphics/GraphicsCache.h"
 #include "graphics/GraphicsCacheItem.h"
 #include "graphics/GraphicsImage.h"
@@ -41,6 +43,7 @@
 #include "support/types.h"
 
 #include <QCheckBox>
+#include <QFileDialog>
 #include <QLabel>
 #include <QLineEdit>
 #include <QPushButton>
@@ -74,7 +77,7 @@ char const * const rorigin_gui_strs[] = {
 
 size_t const rorigin_size = sizeof(rorigin_lyx_strs) / sizeof(char *);
 
-static string autostr = N_("automatically");
+static string const autostr = N_("automatically");
 
 } // namespace anon
 
@@ -109,7 +112,7 @@ static void setAutoTextCB(QCheckBox * checkBox, QLineEdit * lineEdit,
 
 
 GuiGraphics::GuiGraphics(GuiView & lv)
-       : GuiDialog(lv, "graphics", qt_("Graphics"))
+       : GuiDialog(lv, "graphics", qt_("Graphics")), bbChanged(false)
 {
        setupUi(this);
        
@@ -126,8 +129,12 @@ GuiGraphics::GuiGraphics(GuiView & lv)
                this, SLOT(change_adaptor()));
        connect(HeightCB, SIGNAL(clicked()),
                this, SLOT(change_adaptor()));
+       connect(Width, SIGNAL(textChanged(const QString &)),
+               this, SLOT(updateAspectRatioStatus()));
        connect(Width, SIGNAL(textChanged(const QString &)),
                this, SLOT(change_adaptor()));
+       connect(Height, SIGNAL(textChanged(const QString &)),
+               this, SLOT(updateAspectRatioStatus()));
        connect(Height, SIGNAL(textChanged(const QString &)),
                this, SLOT(change_adaptor()));
        connect(heightUnit, SIGNAL(selectionChanged(lyx::Length::UNIT)),
@@ -191,8 +198,6 @@ GuiGraphics::GuiGraphics(GuiView & lv)
                this, SLOT(change_adaptor()));
        connect(draftCB, SIGNAL(stateChanged(int)),
                this, SLOT(change_adaptor()));
-       connect(unzipCB, SIGNAL(stateChanged(int)),
-               this, SLOT(change_adaptor()));
        // FIXME: we should connect to clicked() when we move to Qt 4.2 because
        // the toggled(bool) signal is also trigged when we update the widgets
        // (rgh-4/07) this isn't as much or a problem as it was, because we're now
@@ -218,11 +223,9 @@ GuiGraphics::GuiGraphics(GuiView & lv)
        bc().addReadOnly(filenameL);
        bc().addReadOnly(filename);
        bc().addReadOnly(browsePB);
-       bc().addReadOnly(unzipCB);
        bc().addReadOnly(bbFrame);
        bc().addReadOnly(draftCB);
        bc().addReadOnly(clip);
-       bc().addReadOnly(unzipCB);
        bc().addReadOnly(displayGB);
        bc().addReadOnly(sizeGB);
        bc().addReadOnly(rotationGB);
@@ -247,6 +250,13 @@ GuiGraphics::GuiGraphics(GuiView & lv)
 void GuiGraphics::change_adaptor()
 {
        changed();
+       string const fname = fromqstr(filename->text());
+       FileName dest_fname(FileName(fromqstr(bufferFilePath())), fname);
+       Format const * fmt = theFormats().getFormat(theFormats().getFormatFromFile(dest_fname));
+       LYXERR(Debug::GRAPHICS, "fmt: " << fmt
+               << ", fmt_name: " << theFormats().getFormatFromFile(dest_fname));
+       editPB->setEnabled(!fname.empty() && !dest_fname.isDirectory() && dest_fname.exists());
+       chooseSamplePB->setEnabled(!fname.empty() && !dest_fname.isDirectory());
 }
 
 
@@ -358,6 +368,91 @@ void GuiGraphics::on_browsePB_clicked()
 }
 
 
+bool GuiGraphics::checkFileExists()
+{
+       string const fname = fromqstr(filename->text());
+       FileName dest_fname(FileName(fromqstr(bufferFilePath())), fname);
+       if (fname.empty() || !dest_fname.exists()) {
+               return frontend::Alert::prompt(
+                       _("Continue?"), bformat(_("File '%1$s' does not exist. Continue?"), from_utf8(dest_fname.absFileName())),
+                       0, 1, _("&Yes"), _("&No")) == 0;
+       }
+       return true;
+}
+
+
+void GuiGraphics::on_chooseSamplePB_clicked()
+{
+       string fname = fromqstr(filename->text());
+       FileName dest_fname(FileName(fromqstr(bufferFilePath())), fname);
+       string fmt_name = theFormats().getFormatFromFile(FileName(fname));
+       string filter("Any file (*.*)");
+       if (!fmt_name.empty()) {
+               Format const *fmt = theFormats().getFormat(fmt_name);
+               filter = to_utf8(fmt->prettyname()) + " Files (*." + dest_fname.extension() + ")";
+       }
+       if (fname.empty() || dest_fname.isDirectory()) {
+               frontend::Alert::warning(_("Invalid destination file name!"), _("Invalid destination file name!"));
+               return;
+       }
+
+       QString const samplesDir = toqstr(addPath(package().user_support().absFileName(), "samples"));
+       string sample_name = fromqstr(QFileDialog::getOpenFileName(this, toqstr("Please, select sample template"), samplesDir, toqstr(filter)));
+       if (sample_name.empty())
+               // User pressed Cancel
+               return;
+       FileName sample_fname = FileName(sample_name);
+
+       //FileName sample_fname = libFileSearch(toqstr("samples"), toqstr(sample_name));
+       if (sample_fname.isDirectory() || !sample_fname.exists()) {
+               frontend::Alert::warning(_("Invalid sample file name"), _("Invalid sample file name"));
+               return;
+       }
+
+       string sample_fmt_name = theFormats().getFormatFromFile(sample_fname);
+       if (fmt_name.empty() && !sample_fmt_name.empty()) {
+               fmt_name = sample_fmt_name;
+               string ext = theFormats().getFormat(fmt_name)->extension();
+               if (!ext.empty()) {
+                       fname = fname + "." + ext;
+                       dest_fname.set(FileName(fromqstr(bufferFilePath())), fname);
+                       filename->setText(toqstr(fname));
+               }
+       }
+
+       if (fname.empty() || dest_fname.isDirectory()) {
+               frontend::Alert::warning(_("Invalid destination file name!"), _("Cannot copy sample file on an invalid destination file!"));
+               return;
+       }
+
+       if (!dest_fname.exists() || (dest_fname.exists() &&
+               frontend::Alert::prompt(
+                       _("Overwrite?"), bformat(_("File '%1$s' already exists. Overwrite with sample from template?"), from_utf8(dest_fname.absFileName())),
+                       0, 1, _("&Yes"), _("&No")) == 0)) {
+               sample_fname.copyTo(dest_fname);
+               dest_fname.refresh();
+               change_adaptor();
+       }
+}
+
+
+void GuiGraphics::on_editPB_clicked()
+{
+       string const fname = fromqstr(filename->text());
+       FileName dest_fname(FileName(fromqstr(bufferFilePath())), fname);
+       string fmt_name = theFormats().getFormatFromFile(FileName(fname));
+       if (checkFileExists())
+               theFormats().edit(buffer(), dest_fname, fmt_name);
+}
+
+
+void GuiGraphics::on_okPB_clicked()
+{
+       if (checkFileExists())
+               applyView();
+}
+
+
 void GuiGraphics::on_getPB_clicked()
 {
        getBB();
@@ -398,15 +493,13 @@ void GuiGraphics::on_scaleCB_toggled(bool setScale)
        Height->setEnabled(false);
        heightUnit->setEnabled(false);
 
-       aspectratio->setDisabled(true);
-       aspectratio->setChecked(true);
-
        rotateOrderCB->setEnabled((WidthCB->isChecked() ||
                                 HeightCB->isChecked() ||
                                 scaleCB->isChecked()) &&
                                 (angle->text() != "0"));
 
        setAutoText();
+       updateAspectRatioStatus();
 }
 
 
@@ -418,11 +511,6 @@ void GuiGraphics::on_WidthCB_toggled(bool setWidth)
                Width->setFocus(Qt::OtherFocusReason);
 
        bool const setHeight = HeightCB->isChecked();
-       aspectratio->setEnabled(setWidth && setHeight);
-       aspectratio->blockSignals(true);
-       aspectratio->setChecked(!(setWidth && setHeight));
-       aspectratio->blockSignals(false);
-
        scaleCB->setEnabled(!setWidth && !setHeight);
        //already will be unchecked, so don't need to do that
        Scale->setEnabled((!setWidth && !setHeight) //=scaleCB->isEnabled()
@@ -432,6 +520,7 @@ void GuiGraphics::on_WidthCB_toggled(bool setWidth)
                                 (angle->text() != "0"));
 
        setAutoText();
+       updateAspectRatioStatus();
 }
 
 
@@ -443,11 +532,6 @@ void GuiGraphics::on_HeightCB_toggled(bool setHeight)
                Height->setFocus(Qt::OtherFocusReason);
 
        bool const setWidth = WidthCB->isChecked();
-       aspectratio->setEnabled(setWidth && setHeight);
-       aspectratio->blockSignals(true);
-       aspectratio->setChecked(!(setWidth && setHeight));
-       aspectratio->blockSignals(false);
-
        scaleCB->setEnabled(!setWidth && !setHeight);
        //already unchecked
        Scale->setEnabled((!setWidth && !setHeight) //=scaleCB->isEnabled()
@@ -457,6 +541,41 @@ void GuiGraphics::on_HeightCB_toggled(bool setHeight)
                                 (angle->text() != "0"));
 
        setAutoText();
+       updateAspectRatioStatus();
+}
+
+
+void GuiGraphics::updateAspectRatioStatus()
+{
+       // keepaspectratio only makes sense if both a width _and_ a
+       // height are given, since its function is (see graphics manual):
+       // "If set to true then specifying both 'width' and 'height'
+       // (or 'totalheight') does not distort the figure but scales
+       // such that neither of the specified dimensions is _exceeded_."
+       aspectratio->setEnabled(
+               WidthCB->isChecked() && !Width->text().isEmpty()
+               && Width->text() != qt_(autostr)
+               && HeightCB->isChecked() && !Height->text().isEmpty()
+               && Height->text() != qt_(autostr)
+               );
+       if (!aspectratio->isEnabled())
+               aspectratio->setChecked(false);
+}
+
+
+void GuiGraphics::on_aspectratio_toggled(bool aspectratio)
+{
+       if (aspectratio) {
+               WidthCB->setText(qt_("Set max. &width:"));
+               HeightCB->setText(qt_("Set max. &height:"));
+               Width->setToolTip(qt_("Maximal width of image in output"));
+               Height->setToolTip(qt_("Maximal height of image in output"));
+       } else {
+               WidthCB->setText(qt_("Set &width:"));
+               HeightCB->setText(qt_("Set &height:"));
+               Width->setToolTip(qt_("Width of image in output"));
+               Height->setToolTip(qt_("Height of image in output"));
+       }
 }
 
 
@@ -500,7 +619,7 @@ void GuiGraphics::paramsToDialog(InsetGraphicsParams const & igp)
        filename->setText(toqstr(name));
 
        // set the bounding box values
-       if (igp.bb.empty()) {
+       if (igp.bbox.empty()) {
                string const bb = readBoundingBox(igp.filename.absFileName());
                // the values from the file always have the bigpoint-unit bp
                doubleToWidget(lbX, token(bb, ' ', 0));
@@ -514,46 +633,24 @@ void GuiGraphics::paramsToDialog(InsetGraphicsParams const & igp)
                bbChanged = false;
        } else {
                // get the values from the inset
-               Length anyLength;
-               string const xl = token(igp.bb, ' ', 0);
-               string const yl = token(igp.bb, ' ', 1);
-               string const xr = token(igp.bb, ' ', 2);
-               string const yr = token(igp.bb, ' ', 3);
-               if (isValidLength(xl, &anyLength)) {
-                       doubleToWidget(lbX, anyLength.value());
-                       string const unit = unit_name[anyLength.unit()];
-                       lbXunit->setCurrentIndex(lbXunit->findData(toqstr(unit)));
-               } else {
-                       lbX->setText(toqstr(xl));
-               }
-               if (isValidLength(yl, &anyLength)) {
-                       doubleToWidget(lbY, anyLength.value());
-                       string const unit = unit_name[anyLength.unit()];
-                       lbYunit->setCurrentIndex(lbYunit->findData(toqstr(unit)));
-               } else {
-                       lbY->setText(toqstr(xl));
-               }
-               if (isValidLength(xr, &anyLength)) {
-                       doubleToWidget(rtX, anyLength.value());
-                       string const unit = unit_name[anyLength.unit()];
-                       rtXunit->setCurrentIndex(rtXunit->findData(toqstr(unit)));
-               } else {
-                       rtX->setText(toqstr(xl));
-               }
-               if (isValidLength(yr, &anyLength)) {
-                       doubleToWidget(rtY, anyLength.value());
-                       string const unit = unit_name[anyLength.unit()];
-                       rtYunit->setCurrentIndex(rtYunit->findData(toqstr(unit)));
-               } else {
-                       rtY->setText(toqstr(xl));
-               }
+               doubleToWidget(lbX, igp.bbox.xl.value());
+               string unit = unit_name[igp.bbox.xl.unit()];
+               lbXunit->setCurrentIndex(lbXunit->findData(toqstr(unit)));
+               doubleToWidget(lbY, igp.bbox.yb.value());
+               unit = unit_name[igp.bbox.yb.unit()];
+               lbYunit->setCurrentIndex(lbYunit->findData(toqstr(unit)));
+               doubleToWidget(rtX, igp.bbox.xr.value());
+               unit = unit_name[igp.bbox.xr.unit()];
+               rtXunit->setCurrentIndex(rtXunit->findData(toqstr(unit)));
+               doubleToWidget(rtY, igp.bbox.yt.value());
+               unit = unit_name[igp.bbox.yt.unit()];
+               rtYunit->setCurrentIndex(rtYunit->findData(toqstr(unit)));
                bbChanged = true;
        }
 
        // Update the draft and clip mode
        draftCB->setChecked(igp.draft);
        clip->setChecked(igp.clip);
-       unzipCB->setChecked(igp.noUnzip);
        displayGB->setChecked(igp.display);
        displayscale->setText(toqstr(convert<string>(igp.lyxscale)));
 
@@ -574,7 +671,7 @@ void GuiGraphics::paramsToDialog(InsetGraphicsParams const & igp)
        set<string>::const_iterator end = grp.end();
        groupCO->blockSignals(true);
        groupCO->clear();
-       for (; it != end; it++)
+       for (; it != end; ++it)
                groupCO->addItem(toqstr(*it), toqstr(*it));
        groupCO->insertItem(0, qt_("None"), QString());
        if (igp.groupId.empty())
@@ -613,9 +710,9 @@ void GuiGraphics::paramsToDialog(InsetGraphicsParams const & igp)
        scaleCB->setEnabled(!widthChecked && !heightChecked);
        WidthCB->setEnabled(!scaleChecked);
        HeightCB->setEnabled(!scaleChecked);
-       aspectratio->setEnabled(widthChecked && heightChecked);
 
        setAutoText();
+       updateAspectRatioStatus();
 
        doubleToWidget(angle, igp.rotateAngle);
        rotateOrderCB->setChecked(igp.scaleBeforeRotation);
@@ -649,9 +746,8 @@ void GuiGraphics::applyView()
        igp.filename.set(fromqstr(filename->text()), fromqstr(bufferFilePath()));
 
        // the bb section
-       igp.bb.erase();
+       igp.bbox = graphics::BoundingBox();
        if (bbChanged) {
-               string bb;
                string lbXs = widgetToDoubleStr(lbX);
                string lbYs = widgetToDoubleStr(lbY);
                string rtXs = widgetToDoubleStr(rtX);
@@ -661,22 +757,17 @@ void GuiGraphics::applyView()
                        convert<int>(rtXs) + convert<int>(rtXs);
                if (bb_sum) {
                        if (lbXs.empty())
-                               bb = "0 ";
-                       else
-                               bb = lbXs + fromqstr(lbXunit->currentText()) + ' ';
+                               lbXs = "0";
+                       igp.bbox.xl = Length(lbXs + fromqstr(lbXunit->currentText()));
                        if (lbYs.empty())
-                               bb += "0 ";
-                       else
-                               bb += (lbYs + fromqstr(lbYunit->currentText()) + ' ');
+                               lbYs = "0";
+                       igp.bbox.yb = Length(lbYs + fromqstr(lbYunit->currentText()));
                        if (rtXs.empty())
-                               bb += "0 ";
-                       else
-                               bb += (rtXs + fromqstr(rtXunit->currentText()) + ' ');
+                               rtXs = "0";
+                       igp.bbox.xr = Length(rtXs + fromqstr(rtXunit->currentText()));
                        if (rtYs.empty())
-                               bb += '0';
-                       else
-                               bb += (rtYs + fromqstr(rtYunit->currentText()));
-                       igp.bb = bb;
+                               rtYs = "0";
+                       igp.bbox.yt = Length(rtYs + fromqstr(rtYunit->currentText()));
                }
        }
 
@@ -700,12 +791,9 @@ void GuiGraphics::applyView()
                igp.height = HeightCB->isChecked() ?
                        Length(widgetsToLength(Height, heightUnit)) :
                        Length("0pt");
-               igp.keepAspectRatio = aspectratio->isEnabled() &&
-                       aspectratio->isChecked() &&
-                       igp.width.value() > 0 && igp.height.value() > 0;
+               igp.keepAspectRatio = aspectratio->isChecked();
        }
 
-       igp.noUnzip = unzipCB->isChecked();
        igp.lyxscale = displayscale->text().toInt();
        igp.rotateAngle = widgetToDoubleStr(angle);
 
@@ -793,7 +881,7 @@ QString GuiGraphics::browse(QString const & in_name) const
        if (!clip.isDirectory())
                clipdir = addName(package().system_support().absFileName(), "clipart");
 
-       return browseRelFile(in_name, bufferFilePath(),
+       return browseRelToParent(in_name, bufferFilePath(),
                title, fileFilters(QString()), false, 
                qt_("Clipart|#C#c"), toqstr(clipdir),
                qt_("Documents|#o#O"), toqstr(lyxrc.document_path));
@@ -806,7 +894,7 @@ string GuiGraphics::readBoundingBox(string const & file)
 
        // try to get it from the file, if possible. Zipped files are
        // unzipped in the readBB_from_PSFile-Function
-       string const bb = readBB_from_PSFile(abs_file);
+       string const bb = graphics::readBB_from_PSFile(abs_file);
        if (!bb.empty())
                return bb;