2006-06-26 17:18:28 +00:00
|
|
|
// -*- C++ -*-
|
|
|
|
/**
|
2019-07-20 23:06:05 +02:00
|
|
|
* \file qt/GuiClipboard.cpp
|
2006-06-26 17:18:28 +00:00
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
* Licence details can be found in the file COPYING.
|
|
|
|
*
|
|
|
|
* \author John Levon
|
|
|
|
* \author Abdelrazak Younes
|
|
|
|
*
|
|
|
|
* Full author contact details are available in file CREDITS.
|
|
|
|
*/
|
|
|
|
|
2006-07-08 13:27:43 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
2021-02-14 18:56:25 +01:00
|
|
|
#include "GuiApplication.h"
|
2008-02-18 07:14:42 +00:00
|
|
|
#include "GuiClipboard.h"
|
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
#include "Buffer.h"
|
|
|
|
#include "BufferView.h"
|
|
|
|
#include "Cursor.h"
|
2020-10-25 00:47:13 +03:00
|
|
|
#include "FileDialog.h"
|
|
|
|
#include "qt_helpers.h"
|
2006-06-26 17:18:28 +00:00
|
|
|
|
2008-04-30 08:26:40 +00:00
|
|
|
#include "support/lassert.h"
|
2008-02-07 00:05:18 +00:00
|
|
|
#include "support/convert.h"
|
|
|
|
#include "support/debug.h"
|
2020-10-25 00:47:13 +03:00
|
|
|
#include "support/FileName.h"
|
2008-02-07 00:05:18 +00:00
|
|
|
#include "support/filetools.h"
|
|
|
|
#include "support/gettext.h"
|
|
|
|
#include "support/lstrings.h"
|
2010-10-23 00:21:58 +00:00
|
|
|
#include "support/lyxtime.h"
|
2008-05-23 07:52:39 +00:00
|
|
|
|
2014-08-25 20:08:59 +02:00
|
|
|
#ifdef Q_OS_MAC
|
2008-04-10 21:49:34 +00:00
|
|
|
#include "support/linkback/LinkBackProxy.h"
|
2014-08-25 20:08:59 +02:00
|
|
|
#endif // Q_OS_MAC
|
2008-04-10 21:49:34 +00:00
|
|
|
|
|
|
|
#include "frontends/alert.h"
|
2006-06-26 17:18:28 +00:00
|
|
|
|
2020-11-21 15:40:31 +02:00
|
|
|
#include "support/checksum.h"
|
|
|
|
|
2006-06-26 17:18:28 +00:00
|
|
|
#include <QApplication>
|
2008-02-03 10:43:03 +00:00
|
|
|
#include <QBuffer>
|
2006-06-26 17:18:28 +00:00
|
|
|
#include <QClipboard>
|
2008-02-03 10:43:03 +00:00
|
|
|
#include <QDataStream>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QImage>
|
2007-01-13 18:29:50 +00:00
|
|
|
#include <QMimeData>
|
2006-06-26 17:18:28 +00:00
|
|
|
#include <QString>
|
2008-02-03 10:43:03 +00:00
|
|
|
#include <QStringList>
|
2013-04-14 19:45:36 +02:00
|
|
|
#include <QTextDocument>
|
2016-05-07 01:53:04 +01:00
|
|
|
#include <QTimer>
|
2006-06-26 17:18:28 +00:00
|
|
|
|
2008-04-19 10:37:08 +00:00
|
|
|
#include <memory>
|
2008-02-03 10:43:03 +00:00
|
|
|
#include <map>
|
2010-10-23 10:49:45 +00:00
|
|
|
#include <iostream>
|
2008-02-03 10:43:03 +00:00
|
|
|
|
2007-12-12 10:16:00 +00:00
|
|
|
using namespace std;
|
2007-12-12 18:57:56 +00:00
|
|
|
using namespace lyx::support;
|
2007-01-13 18:29:50 +00:00
|
|
|
|
|
|
|
|
2006-06-26 17:18:28 +00:00
|
|
|
namespace lyx {
|
2007-12-12 10:16:00 +00:00
|
|
|
|
2006-06-26 17:18:28 +00:00
|
|
|
namespace frontend {
|
|
|
|
|
2016-04-29 21:45:18 +01:00
|
|
|
static QMimeData const * read_clipboard()
|
2010-10-23 00:21:58 +00:00
|
|
|
{
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "Getting Clipboard");
|
2010-10-23 00:21:58 +00:00
|
|
|
QMimeData const * source =
|
|
|
|
qApp->clipboard()->mimeData(QClipboard::Clipboard);
|
|
|
|
if (!source) {
|
|
|
|
LYXERR0("0 bytes (no QMimeData)");
|
2012-10-26 02:42:27 +02:00
|
|
|
return new QMimeData;
|
2010-10-23 00:21:58 +00:00
|
|
|
}
|
|
|
|
// It appears that doing IO between getting a mimeData object
|
|
|
|
// and using it can cause a crash (maybe Qt used IO
|
|
|
|
// as an excuse to free() it? Anyway let's not introduce
|
|
|
|
// any new IO here, so e.g. leave the following line commented.
|
|
|
|
// lyxerr << "Got Clipboard (" << (long) source << ")\n" ;
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CacheMimeData::update()
|
|
|
|
{
|
|
|
|
time_t const start_time = current_time();
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "Creating CacheMimeData object");
|
2010-10-23 00:21:58 +00:00
|
|
|
cached_formats_ = read_clipboard()->formats();
|
|
|
|
|
Run codespell on src/frontends
Command was:
codespell -w -i 3 -S Makefile.in -L mathed,afe,tthe,ue,fro,uint,larg,alph,te,thes,alle,Claus,pres,pass-thru src/frontends/
2020-06-26 00:04:31 +02:00
|
|
|
// Qt times out after 5 seconds if it does not receive a response.
|
2010-10-23 00:21:58 +00:00
|
|
|
if (current_time() - start_time > 3) {
|
2010-10-23 08:29:57 +00:00
|
|
|
LYXERR0("No timely response from clipboard, perhaps process "
|
|
|
|
<< "holding clipboard is frozen?");
|
2010-10-23 00:21:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-29 21:45:18 +01:00
|
|
|
QByteArray CacheMimeData::data(QString const & mimeType) const
|
2010-10-23 00:21:58 +00:00
|
|
|
{
|
|
|
|
return read_clipboard()->data(mimeType);
|
|
|
|
}
|
|
|
|
|
2008-05-25 07:49:16 +00:00
|
|
|
|
|
|
|
QString const lyxMimeType(){ return "application/x-lyx"; }
|
2013-04-14 19:45:36 +02:00
|
|
|
QString const texMimeType(){ return "text/x-tex"; }
|
|
|
|
QString const latexMimeType(){ return "application/x-latex"; }
|
2008-05-25 07:49:16 +00:00
|
|
|
QString const pdfMimeType(){ return "application/pdf"; }
|
|
|
|
QString const emfMimeType(){ return "image/x-emf"; }
|
|
|
|
QString const wmfMimeType(){ return "image/x-wmf"; }
|
2008-05-25 07:22:45 +00:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
|
2007-09-30 20:28:15 +00:00
|
|
|
GuiClipboard::GuiClipboard()
|
|
|
|
{
|
|
|
|
connect(qApp->clipboard(), SIGNAL(dataChanged()),
|
|
|
|
this, SLOT(on_dataChanged()));
|
2021-02-14 18:56:25 +01:00
|
|
|
if(qApp->clipboard()->supportsFindBuffer()) {
|
|
|
|
connect(qApp->clipboard(), SIGNAL(findBufferChanged()),
|
|
|
|
this, SLOT(on_findChanged()));
|
|
|
|
on_findChanged();
|
|
|
|
}
|
2007-09-30 20:28:15 +00:00
|
|
|
// initialize clipboard status.
|
2016-04-29 21:51:39 +01:00
|
|
|
update();
|
2007-09-30 20:28:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-01-13 18:29:50 +00:00
|
|
|
string const GuiClipboard::getAsLyX() const
|
2006-06-26 17:18:28 +00:00
|
|
|
{
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "GuiClipboard::getAsLyX(): `");
|
2007-01-13 18:29:50 +00:00
|
|
|
// We don't convert encodings here since the encoding of the
|
|
|
|
// clipboard contents is specified in the data itself
|
2010-10-23 00:21:58 +00:00
|
|
|
if (cache_.hasFormat(lyxMimeType())) {
|
2007-01-13 18:29:50 +00:00
|
|
|
// data from ourself or some other LyX instance
|
2010-10-23 00:21:58 +00:00
|
|
|
QByteArray const ar = cache_.data(lyxMimeType());
|
2007-01-13 18:29:50 +00:00
|
|
|
string const s(ar.data(), ar.count());
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, s << "'");
|
2007-01-13 18:29:50 +00:00
|
|
|
return s;
|
|
|
|
}
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "'");
|
2007-01-13 18:29:50 +00:00
|
|
|
return string();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
FileName GuiClipboard::getPastedGraphicsFileName(Cursor const & cur,
|
|
|
|
Clipboard::GraphicsType & type) const
|
|
|
|
{
|
|
|
|
// create file dialog filter according to the existing types in the clipboard
|
|
|
|
vector<Clipboard::GraphicsType> types;
|
2008-04-07 07:28:03 +00:00
|
|
|
if (hasGraphicsContents(Clipboard::EmfGraphicsType))
|
|
|
|
types.push_back(Clipboard::EmfGraphicsType);
|
|
|
|
if (hasGraphicsContents(Clipboard::WmfGraphicsType))
|
|
|
|
types.push_back(Clipboard::WmfGraphicsType);
|
2008-02-03 10:43:03 +00:00
|
|
|
if (hasGraphicsContents(Clipboard::LinkBackGraphicsType))
|
|
|
|
types.push_back(Clipboard::LinkBackGraphicsType);
|
|
|
|
if (hasGraphicsContents(Clipboard::PdfGraphicsType))
|
|
|
|
types.push_back(Clipboard::PdfGraphicsType);
|
|
|
|
if (hasGraphicsContents(Clipboard::PngGraphicsType))
|
|
|
|
types.push_back(Clipboard::PngGraphicsType);
|
|
|
|
if (hasGraphicsContents(Clipboard::JpegGraphicsType))
|
|
|
|
types.push_back(Clipboard::JpegGraphicsType);
|
2013-04-27 18:12:27 -04:00
|
|
|
|
2013-04-25 17:27:10 -04:00
|
|
|
LASSERT(!types.empty(), return FileName());
|
2013-04-27 18:12:27 -04:00
|
|
|
|
Run codespell on src/frontends
Command was:
codespell -w -i 3 -S Makefile.in -L mathed,afe,tthe,ue,fro,uint,larg,alph,te,thes,alle,Claus,pres,pass-thru src/frontends/
2020-06-26 00:04:31 +02:00
|
|
|
// select preferred type if AnyGraphicsType was passed
|
2008-02-03 10:43:03 +00:00
|
|
|
if (type == Clipboard::AnyGraphicsType)
|
|
|
|
type = types.front();
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// which extension?
|
|
|
|
map<Clipboard::GraphicsType, string> extensions;
|
|
|
|
map<Clipboard::GraphicsType, docstring> typeNames;
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-04-07 07:28:03 +00:00
|
|
|
extensions[Clipboard::EmfGraphicsType] = "emf";
|
|
|
|
extensions[Clipboard::WmfGraphicsType] = "wmf";
|
2008-02-03 10:43:03 +00:00
|
|
|
extensions[Clipboard::LinkBackGraphicsType] = "linkback";
|
|
|
|
extensions[Clipboard::PdfGraphicsType] = "pdf";
|
|
|
|
extensions[Clipboard::PngGraphicsType] = "png";
|
|
|
|
extensions[Clipboard::JpegGraphicsType] = "jpeg";
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-04-07 07:28:03 +00:00
|
|
|
typeNames[Clipboard::EmfGraphicsType] = _("Enhanced Metafile");
|
|
|
|
typeNames[Clipboard::WmfGraphicsType] = _("Windows Metafile");
|
2008-02-03 10:43:03 +00:00
|
|
|
typeNames[Clipboard::LinkBackGraphicsType] = _("LinkBack PDF");
|
|
|
|
typeNames[Clipboard::PdfGraphicsType] = _("PDF");
|
|
|
|
typeNames[Clipboard::PngGraphicsType] = _("PNG");
|
|
|
|
typeNames[Clipboard::JpegGraphicsType] = _("JPEG");
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// find unused filename with primary extension
|
2010-04-21 01:19:09 +00:00
|
|
|
string document_path = cur.buffer()->fileName().onlyPath().absFileName();
|
2008-02-03 10:43:03 +00:00
|
|
|
unsigned newfile_number = 0;
|
|
|
|
FileName filename;
|
|
|
|
do {
|
|
|
|
++newfile_number;
|
2008-02-27 22:23:12 +00:00
|
|
|
filename = FileName(addName(document_path,
|
2008-02-03 10:43:03 +00:00
|
|
|
to_utf8(_("pasted"))
|
|
|
|
+ convert<string>(newfile_number) + "."
|
|
|
|
+ extensions[type]));
|
|
|
|
} while (filename.isReadableFile());
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
while (true) {
|
Run codespell on src/frontends
Command was:
codespell -w -i 3 -S Makefile.in -L mathed,afe,tthe,ue,fro,uint,larg,alph,te,thes,alle,Claus,pres,pass-thru src/frontends/
2020-06-26 00:04:31 +02:00
|
|
|
// create file type filter, putting the preferred on to the front
|
2008-04-20 19:56:01 +00:00
|
|
|
QStringList filter;
|
2008-02-27 22:23:12 +00:00
|
|
|
for (size_t i = 0; i != types.size(); ++i) {
|
2008-02-03 10:43:03 +00:00
|
|
|
docstring s = bformat(_("%1$s Files"), typeNames[types[i]])
|
2008-02-27 22:23:12 +00:00
|
|
|
+ " (*." + from_ascii(extensions[types[i]]) + ")";
|
2008-02-03 10:43:03 +00:00
|
|
|
if (types[i] == type)
|
2008-04-20 19:56:01 +00:00
|
|
|
filter.prepend(toqstr(s));
|
2008-02-03 10:43:03 +00:00
|
|
|
else
|
2008-04-20 19:56:01 +00:00
|
|
|
filter.append(toqstr(s));
|
2008-02-03 10:43:03 +00:00
|
|
|
}
|
2008-04-20 19:56:01 +00:00
|
|
|
filter = fileFilters(filter.join(";;"));
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// show save dialog for the graphic
|
2008-03-05 23:10:53 +00:00
|
|
|
FileDialog dlg(qt_("Choose a filename to save the pasted graphic as"));
|
2008-02-03 10:43:03 +00:00
|
|
|
FileDialog::Result result =
|
2010-04-21 01:19:09 +00:00
|
|
|
dlg.save(toqstr(filename.onlyPath().absFileName()), filter,
|
2008-03-05 23:10:53 +00:00
|
|
|
toqstr(filename.onlyFileName()));
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
if (result.first == FileDialog::Later)
|
|
|
|
return FileName();
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-03-05 23:10:53 +00:00
|
|
|
string newFilename = fromqstr(result.second);
|
2008-02-03 10:43:03 +00:00
|
|
|
if (newFilename.empty()) {
|
|
|
|
cur.bv().message(_("Canceled."));
|
|
|
|
return FileName();
|
|
|
|
}
|
|
|
|
filename.set(newFilename);
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// check the extension (the user could have changed it)
|
2010-04-21 01:19:09 +00:00
|
|
|
if (!suffixIs(ascii_lowercase(filename.absFileName()),
|
2008-02-03 10:43:03 +00:00
|
|
|
"." + extensions[type])) {
|
|
|
|
// the user changed the extension. Check if the type is available
|
2008-02-27 22:23:12 +00:00
|
|
|
size_t i;
|
|
|
|
for (i = 1; i != types.size(); ++i) {
|
2010-04-21 01:19:09 +00:00
|
|
|
if (suffixIs(ascii_lowercase(filename.absFileName()),
|
2008-02-03 10:43:03 +00:00
|
|
|
"." + extensions[types[i]])) {
|
|
|
|
type = types[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// invalid extension found, or none at all. In the latter
|
|
|
|
// case set the default extensions.
|
|
|
|
if (i == types.size()
|
|
|
|
&& filename.onlyFileName().find('.') == string::npos) {
|
|
|
|
filename.changeExtension("." + extensions[type]);
|
|
|
|
}
|
|
|
|
}
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// check whether the file exists and warn the user
|
|
|
|
if (!filename.exists())
|
|
|
|
break;
|
|
|
|
int ret = frontend::Alert::prompt(
|
|
|
|
_("Overwrite external file?"),
|
2008-03-17 02:49:47 +00:00
|
|
|
bformat(_("File %1$s already exists, do you want to overwrite it?"),
|
2010-04-21 01:19:09 +00:00
|
|
|
from_utf8(filename.absFileName())), 1, 1, _("&Overwrite"), _("&Cancel"));
|
2008-02-03 10:43:03 +00:00
|
|
|
if (ret == 0)
|
|
|
|
// overwrite, hence break the dialog loop
|
|
|
|
break;
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// not overwrite, hence show the dialog again (i.e. loop)
|
|
|
|
}
|
2013-04-16 21:50:55 +02:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FileName GuiClipboard::getAsGraphics(Cursor const & cur, GraphicsType type) const
|
|
|
|
{
|
|
|
|
// get the filename from the user
|
|
|
|
FileName filename = getPastedGraphicsFileName(cur, type);
|
|
|
|
if (filename.empty())
|
|
|
|
return FileName();
|
|
|
|
|
|
|
|
// handle image cases first
|
|
|
|
if (type == PngGraphicsType || type == JpegGraphicsType) {
|
|
|
|
// get image from QImage from clipboard
|
|
|
|
QImage image = qApp->clipboard()->image();
|
|
|
|
if (image.isNull()) {
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "No image in clipboard");
|
2008-02-03 10:43:03 +00:00
|
|
|
return FileName();
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert into graphics format
|
|
|
|
QByteArray ar;
|
|
|
|
QBuffer buffer(&ar);
|
|
|
|
buffer.open(QIODevice::WriteOnly);
|
|
|
|
if (type == PngGraphicsType)
|
2010-04-21 01:19:09 +00:00
|
|
|
image.save(toqstr(filename.absFileName()), "PNG");
|
2008-02-03 10:43:03 +00:00
|
|
|
else if (type == JpegGraphicsType)
|
2010-04-21 01:19:09 +00:00
|
|
|
image.save(toqstr(filename.absFileName()), "JPEG");
|
2008-02-03 10:43:03 +00:00
|
|
|
else
|
2013-04-25 17:27:10 -04:00
|
|
|
LATTEST(false);
|
2016-04-29 21:45:18 +01:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
return filename;
|
|
|
|
}
|
2016-04-29 21:45:18 +01:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// get mime for type
|
|
|
|
QString mime;
|
|
|
|
switch (type) {
|
2008-05-25 07:49:16 +00:00
|
|
|
case PdfGraphicsType: mime = pdfMimeType(); break;
|
|
|
|
case LinkBackGraphicsType: mime = pdfMimeType(); break;
|
|
|
|
case EmfGraphicsType: mime = emfMimeType(); break;
|
|
|
|
case WmfGraphicsType: mime = wmfMimeType(); break;
|
2013-04-25 17:27:10 -04:00
|
|
|
default: LASSERT(false, return FileName());
|
2008-02-03 10:43:03 +00:00
|
|
|
}
|
2016-04-29 21:45:18 +01:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// get data
|
2010-10-23 00:21:58 +00:00
|
|
|
if (!cache_.hasFormat(mime))
|
2008-02-03 10:43:03 +00:00
|
|
|
return FileName();
|
|
|
|
// data from ourself or some other LyX instance
|
2010-10-23 00:21:58 +00:00
|
|
|
QByteArray const ar = cache_.data(mime);
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "Getting from clipboard: mime = " << mime.constData()
|
2008-02-03 10:43:03 +00:00
|
|
|
<< "length = " << ar.count());
|
2013-04-12 22:12:47 +02:00
|
|
|
|
2010-04-21 01:19:09 +00:00
|
|
|
QFile f(toqstr(filename.absFileName()));
|
2008-02-03 10:43:03 +00:00
|
|
|
if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "Error opening file "
|
2010-04-21 01:19:09 +00:00
|
|
|
<< filename.absFileName() << " for writing");
|
2008-02-03 10:43:03 +00:00
|
|
|
return FileName();
|
|
|
|
}
|
2016-04-29 21:45:18 +01:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// write the (LinkBack) PDF data
|
|
|
|
f.write(ar);
|
|
|
|
if (type == LinkBackGraphicsType) {
|
2014-08-25 20:08:59 +02:00
|
|
|
#ifdef Q_OS_MAC
|
2008-02-03 10:43:03 +00:00
|
|
|
void const * linkBackData;
|
|
|
|
unsigned linkBackLen;
|
|
|
|
getLinkBackData(&linkBackData, &linkBackLen);
|
|
|
|
f.write((char *)linkBackData, linkBackLen);
|
|
|
|
quint32 pdfLen = ar.size();
|
|
|
|
QDataStream ds(&f);
|
|
|
|
ds << pdfLen; // big endian by default
|
|
|
|
#else
|
|
|
|
// only non-Mac this should never happen
|
2013-04-25 17:27:10 -04:00
|
|
|
LATTEST(false);
|
2014-08-25 20:08:59 +02:00
|
|
|
#endif // Q_OS_MAC
|
2008-02-03 10:43:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
f.close();
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-14 19:45:36 +02:00
|
|
|
namespace {
|
|
|
|
/**
|
|
|
|
* Tidy up a HTML chunk coming from the clipboard.
|
|
|
|
* This is needed since different applications put different kinds of HTML
|
|
|
|
* on the clipboard:
|
|
|
|
* - With or without the <?xml> tag
|
|
|
|
* - With or without the <!DOCTYPE> tag
|
|
|
|
* - With or without the <html> tag
|
|
|
|
* - With or without the <body> tag
|
|
|
|
* - With or without the <p> tag
|
|
|
|
* Since we are going to write a HTML file for external converters we need
|
|
|
|
* to ensure that it is a well formed HTML file, including all the mentioned tags.
|
|
|
|
*/
|
2020-10-31 15:09:46 +02:00
|
|
|
QString tidyHtml(QString const & input)
|
2013-04-14 19:45:36 +02:00
|
|
|
{
|
|
|
|
// Misuse QTextDocument to cleanup the HTML.
|
|
|
|
// As a side effect, all visual markup like <tt> is converted to CSS,
|
|
|
|
// which is ignored by gnuhtml2latex.
|
|
|
|
// While this may be seen as a bug by some people it is actually a
|
|
|
|
// good thing, since we do import structure, but ignore all visual
|
|
|
|
// clutter.
|
|
|
|
QTextDocument converter;
|
|
|
|
converter.setHtml(input);
|
Allow compiling with Qt6
This commit allows compiling LyX with Qt6 when using autotools.
For a successful compilation the following 2 conditions must be met.
1) The Qt6 qmake has to come first in PATH, so that the command
"qmake -v | grep -o 'Qt version .'" returns "Qt version 6".
2) The --enable-qt6 switch has to be passed to the configure command.
If --enable-qt6 is used but Qt6 is not found, Qt5 is tried as a fallback.
If also Qt5 is not found, configuring for Qt4 is attempted.
If --enable-qt6 is not used, then things go as usual. This means that Qt5
is tried first and then Qt4, unless --disable-qt5 is used, in which case
Qt4 is directly attempted. This means that existing scripts should
continue working unmodified.
LyX should compile with Qt6 on windows and linux, and possibly also on
mac, but I could not test that. However, it is not guaranteed that it
works as it should. In particular I am not sure that I got right the
conversion from QRegExp to QRegularExpression. For sure, the syntax
highlighting seems to not work right. Someone in the know should take
a look at that. I am able to load documents and compile them but some
thourough testing is needed. However, when compiling for Qt5 or Qt4,
I tried to make sure that the functionality is preserved.
2021-03-15 17:09:09 +01:00
|
|
|
#if QT_VERSION < 0x060000
|
2013-04-14 19:45:36 +02:00
|
|
|
return converter.toHtml("utf-8");
|
Allow compiling with Qt6
This commit allows compiling LyX with Qt6 when using autotools.
For a successful compilation the following 2 conditions must be met.
1) The Qt6 qmake has to come first in PATH, so that the command
"qmake -v | grep -o 'Qt version .'" returns "Qt version 6".
2) The --enable-qt6 switch has to be passed to the configure command.
If --enable-qt6 is used but Qt6 is not found, Qt5 is tried as a fallback.
If also Qt5 is not found, configuring for Qt4 is attempted.
If --enable-qt6 is not used, then things go as usual. This means that Qt5
is tried first and then Qt4, unless --disable-qt5 is used, in which case
Qt4 is directly attempted. This means that existing scripts should
continue working unmodified.
LyX should compile with Qt6 on windows and linux, and possibly also on
mac, but I could not test that. However, it is not guaranteed that it
works as it should. In particular I am not sure that I got right the
conversion from QRegExp to QRegularExpression. For sure, the syntax
highlighting seems to not work right. Someone in the know should take
a look at that. I am able to load documents and compile them but some
thourough testing is needed. However, when compiling for Qt5 or Qt4,
I tried to make sure that the functionality is preserved.
2021-03-15 17:09:09 +01:00
|
|
|
#else
|
|
|
|
return converter.toHtml();
|
|
|
|
#endif
|
2013-04-14 19:45:36 +02:00
|
|
|
}
|
2017-07-23 13:11:54 +02:00
|
|
|
} // namespace
|
2013-04-14 19:45:36 +02:00
|
|
|
|
|
|
|
|
|
|
|
docstring const GuiClipboard::getAsText(TextType type) const
|
2007-01-13 18:29:50 +00:00
|
|
|
{
|
|
|
|
// text data from other applications
|
2013-04-14 19:45:36 +02:00
|
|
|
if ((type == AnyTextType || type == LyXOrPlainTextType) && hasTextContents(LyXTextType))
|
|
|
|
type = LyXTextType;
|
|
|
|
if (type == AnyTextType && hasTextContents(LaTeXTextType))
|
|
|
|
type = LaTeXTextType;
|
|
|
|
if (type == AnyTextType && hasTextContents(HtmlTextType))
|
|
|
|
type = HtmlTextType;
|
|
|
|
QString str;
|
|
|
|
switch (type) {
|
|
|
|
case LyXTextType:
|
|
|
|
// must not convert to docstring, since file can contain
|
|
|
|
// mixed encodings (use getAsLyX() instead)
|
|
|
|
break;
|
|
|
|
case AnyTextType:
|
|
|
|
case LyXOrPlainTextType:
|
|
|
|
case PlainTextType:
|
|
|
|
str = qApp->clipboard()->text(QClipboard::Clipboard)
|
2007-07-05 14:45:00 +00:00
|
|
|
.normalized(QString::NormalizationForm_C);
|
2013-04-14 19:45:36 +02:00
|
|
|
break;
|
|
|
|
case LaTeXTextType: {
|
|
|
|
QMimeData const * source =
|
|
|
|
qApp->clipboard()->mimeData(QClipboard::Clipboard);
|
|
|
|
if (source) {
|
|
|
|
// First try LaTeX, then TeX (we do not distinguish
|
|
|
|
// for clipboard purposes)
|
|
|
|
if (source->hasFormat(latexMimeType())) {
|
|
|
|
str = source->data(latexMimeType());
|
|
|
|
str = str.normalized(QString::NormalizationForm_C);
|
|
|
|
} else if (source->hasFormat(texMimeType())) {
|
|
|
|
str = source->data(texMimeType());
|
|
|
|
str = str.normalized(QString::NormalizationForm_C);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case HtmlTextType: {
|
|
|
|
QString subtype = "html";
|
|
|
|
str = qApp->clipboard()->text(subtype, QClipboard::Clipboard)
|
|
|
|
.normalized(QString::NormalizationForm_C);
|
|
|
|
str = tidyHtml(str);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "GuiClipboard::getAsText(" << type << "): `" << str << "'");
|
2006-06-26 17:18:28 +00:00
|
|
|
if (str.isNull())
|
2006-09-03 07:02:38 +00:00
|
|
|
return docstring();
|
2006-06-26 17:18:28 +00:00
|
|
|
|
2008-10-09 07:21:48 +00:00
|
|
|
return internalLineEnding(str);
|
2006-06-26 17:18:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-29 15:28:21 +02:00
|
|
|
void GuiClipboard::put(string const & text) const
|
|
|
|
{
|
|
|
|
qApp->clipboard()->setText(toqstr(text));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-12 22:12:47 +02:00
|
|
|
void GuiClipboard::put(string const & lyx, docstring const & html, docstring const & text)
|
2006-06-26 17:18:28 +00:00
|
|
|
{
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "GuiClipboard::put(`" << lyx << "' `"
|
2013-04-12 22:12:47 +02:00
|
|
|
<< to_utf8(html) << "' `" << to_utf8(text) << "')");
|
2007-01-13 18:29:50 +00:00
|
|
|
// We don't convert the encoding of lyx since the encoding of the
|
|
|
|
// clipboard contents is specified in the data itself
|
|
|
|
QMimeData * data = new QMimeData;
|
|
|
|
if (!lyx.empty()) {
|
|
|
|
QByteArray const qlyx(lyx.c_str(), lyx.size());
|
2008-05-25 07:49:16 +00:00
|
|
|
data->setData(lyxMimeType(), qlyx);
|
2010-12-11 23:04:24 +00:00
|
|
|
// If the OS has not the concept of clipboard ownership,
|
|
|
|
// we recognize internal data through its checksum.
|
2020-11-21 15:40:31 +02:00
|
|
|
if (!hasInternal())
|
|
|
|
checksum = support::checksum(lyx);
|
2007-01-13 18:29:50 +00:00
|
|
|
}
|
|
|
|
// Don't test for text.empty() since we want to be able to clear the
|
|
|
|
// clipboard.
|
|
|
|
QString const qtext = toqstr(text);
|
|
|
|
data->setText(qtext);
|
2013-04-12 22:12:47 +02:00
|
|
|
QString const qhtml = toqstr(html);
|
|
|
|
data->setHtml(qhtml);
|
2007-01-13 18:29:50 +00:00
|
|
|
qApp->clipboard()->setMimeData(data, QClipboard::Clipboard);
|
|
|
|
}
|
|
|
|
|
2006-06-26 17:18:28 +00:00
|
|
|
|
2013-04-14 19:45:36 +02:00
|
|
|
bool GuiClipboard::hasTextContents(Clipboard::TextType type) const
|
2009-01-04 23:31:32 +00:00
|
|
|
{
|
2013-04-14 19:45:36 +02:00
|
|
|
switch (type) {
|
|
|
|
case AnyTextType:
|
|
|
|
return cache_.hasFormat(lyxMimeType()) || cache_.hasText() ||
|
|
|
|
cache_.hasHtml() || cache_.hasFormat(latexMimeType()) ||
|
|
|
|
cache_.hasFormat(texMimeType());
|
|
|
|
case LyXOrPlainTextType:
|
|
|
|
return cache_.hasFormat(lyxMimeType()) || cache_.hasText();
|
|
|
|
case LyXTextType:
|
|
|
|
return cache_.hasFormat(lyxMimeType());
|
|
|
|
case PlainTextType:
|
2016-04-29 21:45:18 +01:00
|
|
|
return cache_.hasText();
|
2013-04-14 19:45:36 +02:00
|
|
|
case HtmlTextType:
|
|
|
|
return cache_.hasHtml();
|
|
|
|
case LaTeXTextType:
|
|
|
|
return cache_.hasFormat(latexMimeType()) ||
|
|
|
|
cache_.hasFormat(texMimeType());
|
|
|
|
}
|
|
|
|
// shut up compiler
|
|
|
|
return false;
|
2009-01-04 23:31:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
bool GuiClipboard::hasGraphicsContents(Clipboard::GraphicsType type) const
|
|
|
|
{
|
|
|
|
if (type == AnyGraphicsType) {
|
|
|
|
return hasGraphicsContents(PdfGraphicsType)
|
|
|
|
|| hasGraphicsContents(PngGraphicsType)
|
|
|
|
|| hasGraphicsContents(JpegGraphicsType)
|
2008-04-07 07:28:03 +00:00
|
|
|
|| hasGraphicsContents(EmfGraphicsType)
|
|
|
|
|| hasGraphicsContents(WmfGraphicsType)
|
2008-02-03 10:43:03 +00:00
|
|
|
|| hasGraphicsContents(LinkBackGraphicsType);
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle image cases first
|
|
|
|
if (type == PngGraphicsType || type == JpegGraphicsType)
|
2010-10-23 00:21:58 +00:00
|
|
|
return cache_.hasImage();
|
2008-02-03 10:43:03 +00:00
|
|
|
|
|
|
|
// handle LinkBack for Mac
|
|
|
|
if (type == LinkBackGraphicsType)
|
2014-08-25 20:08:59 +02:00
|
|
|
#ifdef Q_OS_MAC
|
2008-02-03 10:43:03 +00:00
|
|
|
return isLinkBackDataInPasteboard();
|
|
|
|
#else
|
|
|
|
return false;
|
2014-08-25 20:08:59 +02:00
|
|
|
#endif // Q_OS_MAC
|
2016-04-29 21:45:18 +01:00
|
|
|
|
2008-02-03 10:43:03 +00:00
|
|
|
// get mime data
|
2010-10-23 00:21:58 +00:00
|
|
|
QStringList const & formats = cache_.formats();
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "We found " << formats.size() << " formats");
|
2008-05-23 07:52:39 +00:00
|
|
|
for (int i = 0; i < formats.size(); ++i)
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "Found format " << formats[i]);
|
2008-02-03 10:43:03 +00:00
|
|
|
|
|
|
|
// compute mime for type
|
|
|
|
QString mime;
|
|
|
|
switch (type) {
|
2008-05-25 07:49:16 +00:00
|
|
|
case EmfGraphicsType: mime = emfMimeType(); break;
|
|
|
|
case WmfGraphicsType: mime = wmfMimeType(); break;
|
|
|
|
case PdfGraphicsType: mime = pdfMimeType(); break;
|
2013-04-25 17:27:10 -04:00
|
|
|
default: LASSERT(false, return false);
|
2008-02-03 10:43:03 +00:00
|
|
|
}
|
2016-04-29 21:45:18 +01:00
|
|
|
|
2010-10-23 00:21:58 +00:00
|
|
|
return cache_.hasFormat(mime);
|
2006-06-26 17:18:28 +00:00
|
|
|
}
|
|
|
|
|
2007-01-03 08:53:54 +00:00
|
|
|
|
|
|
|
bool GuiClipboard::isInternal() const
|
|
|
|
{
|
2013-04-14 19:45:36 +02:00
|
|
|
if (!hasTextContents(LyXTextType))
|
2010-12-11 23:04:24 +00:00
|
|
|
return false;
|
|
|
|
|
2007-01-27 16:55:25 +00:00
|
|
|
// ownsClipboard() is also true for stuff coming from dialogs, e.g.
|
2010-12-11 23:04:24 +00:00
|
|
|
// the preamble dialog. This does only work on X11 and Windows, since
|
|
|
|
// ownsClipboard() is hardwired to return false on OS X.
|
|
|
|
if (hasInternal())
|
|
|
|
return qApp->clipboard()->ownsClipboard();
|
|
|
|
|
|
|
|
// We are running on OS X: Check whether clipboard data is from
|
|
|
|
// ourself by comparing its checksum with the stored one.
|
|
|
|
QByteArray const ar = cache_.data(lyxMimeType());
|
|
|
|
string const data(ar.data(), ar.count());
|
2020-11-21 15:40:31 +02:00
|
|
|
return checksum == static_cast<std::uint32_t>(support::checksum(data));
|
2007-01-03 08:53:54 +00:00
|
|
|
}
|
|
|
|
|
2007-01-07 16:43:38 +00:00
|
|
|
|
2007-12-28 15:56:05 +00:00
|
|
|
bool GuiClipboard::hasInternal() const
|
|
|
|
{
|
|
|
|
// Windows and Mac OS X does not have the concept of ownership;
|
2016-04-29 21:45:18 +01:00
|
|
|
// the clipboard is a fully global resource so all applications
|
2010-12-11 23:04:24 +00:00
|
|
|
// are notified of changes. However, on Windows ownership is
|
|
|
|
// emulated by Qt through the OleIsCurrentClipboard() API, while
|
|
|
|
// on Mac OS X we deal with this issue by ourself.
|
2015-01-11 19:36:41 +01:00
|
|
|
#ifndef Q_OS_MAC
|
2007-12-28 15:56:05 +00:00
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-02-14 18:56:25 +01:00
|
|
|
void GuiClipboard::setFindBuffer(docstring const & text)
|
|
|
|
{
|
|
|
|
LYXERR(Debug::CLIPBOARD, "new findbuffer: " << text);
|
|
|
|
Clipboard::setFindBuffer(text);
|
2021-02-14 22:18:07 +01:00
|
|
|
if(qApp->clipboard()->supportsFindBuffer()) {
|
|
|
|
qApp->clipboard()->setText(toqstr(text), QClipboard::FindBuffer);
|
|
|
|
}
|
2021-02-14 18:56:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GuiClipboard::on_findChanged()
|
|
|
|
{
|
|
|
|
Clipboard::setFindBuffer(from_utf8(fromqstr(
|
|
|
|
qApp->clipboard()->text(QClipboard::FindBuffer))));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-30 20:28:15 +00:00
|
|
|
void GuiClipboard::on_dataChanged()
|
2016-04-29 21:51:39 +01:00
|
|
|
{
|
|
|
|
update();
|
|
|
|
#if defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN)
|
|
|
|
// Retry on Windows (#10109)
|
|
|
|
if (cache_.formats().count() == 0) {
|
|
|
|
QTimer::singleShot(100, this, SLOT(update()));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void GuiClipboard::update()
|
2007-09-30 20:28:15 +00:00
|
|
|
{
|
2010-10-23 00:21:58 +00:00
|
|
|
//Note: we do not really need to run cache_.update() unless the
|
|
|
|
//data has been changed *and* the GuiClipboard has been queried.
|
|
|
|
//However if run cache_.update() the moment a process grabs the
|
|
|
|
//clipboard, the process holding the clipboard presumably won't
|
|
|
|
//yet be frozen, and so we won't need to wait 5 seconds for Qt
|
|
|
|
//to time-out waiting for the clipboard.
|
|
|
|
cache_.update();
|
|
|
|
QStringList l = cache_.formats();
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, "Qt Clipboard changed. We found the following mime types:");
|
2008-04-20 21:05:35 +00:00
|
|
|
for (int i = 0; i < l.count(); i++)
|
2015-07-08 10:57:04 +02:00
|
|
|
LYXERR(Debug::CLIPBOARD, l.value(i));
|
2013-04-12 22:12:47 +02:00
|
|
|
|
2013-04-14 19:45:36 +02:00
|
|
|
plaintext_clipboard_empty_ = qApp->clipboard()->
|
2007-09-30 20:28:15 +00:00
|
|
|
text(QClipboard::Clipboard).isEmpty();
|
|
|
|
|
2013-04-14 19:45:36 +02:00
|
|
|
has_text_contents_ = hasTextContents();
|
2008-02-03 10:43:03 +00:00
|
|
|
has_graphics_contents_ = hasGraphicsContents();
|
2007-09-30 20:28:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-01-07 16:43:38 +00:00
|
|
|
bool GuiClipboard::empty() const
|
|
|
|
{
|
2007-02-21 21:47:44 +00:00
|
|
|
// We need to check both the plaintext and the LyX version of the
|
|
|
|
// clipboard. The plaintext version is empty if the LyX version
|
2007-09-30 20:28:15 +00:00
|
|
|
// contains only one inset, and the LyX version is empty if the
|
2007-02-21 21:47:44 +00:00
|
|
|
// clipboard does not come from LyX.
|
2013-04-14 19:45:36 +02:00
|
|
|
if (!plaintext_clipboard_empty_)
|
2007-02-21 21:47:44 +00:00
|
|
|
return false;
|
2013-04-14 19:45:36 +02:00
|
|
|
return !has_text_contents_ && !has_graphics_contents_;
|
2007-01-07 16:43:38 +00:00
|
|
|
}
|
|
|
|
|
2006-06-26 17:18:28 +00:00
|
|
|
} // namespace frontend
|
|
|
|
} // namespace lyx
|
2007-09-30 20:28:15 +00:00
|
|
|
|
2008-11-14 14:28:50 +00:00
|
|
|
#include "moc_GuiClipboard.cpp"
|