mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-16 16:18:22 +00:00
ecef54500d
so we can write a limited amount when using this for TOC and tooltip output. This should solve the problem with slowness that Kornel noticed, which was caused by our trying to write an entire plaintext bibliography every time we updated the TOC. We did that because he had a bibliography inside a branch, and we use plaintext for creating the tooltip that goes with the branch list. Other related bugs were fixed along the way. E.g., it turns out that, if someone had an InsetInclude inside a branch, then we would have been writing a *plaintext file* for that inset every time we updated the TOC. I wonder if some of the other reports of slowness we have received might be due to this kind of issue?
297 lines
7.6 KiB
C++
297 lines
7.6 KiB
C++
/**
|
|
* \file InsetHyperlink.cpp
|
|
* This file is part of LyX, the document processor.
|
|
* Licence details can be found in the file COPYING.
|
|
*
|
|
* \author José Matos
|
|
* \author Uwe Stöhr
|
|
*
|
|
* Full author contact details are available in file CREDITS.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include "InsetHyperlink.h"
|
|
|
|
#include "Buffer.h"
|
|
#include "DispatchResult.h"
|
|
#include "Encoding.h"
|
|
#include "Format.h"
|
|
#include "FuncRequest.h"
|
|
#include "FuncStatus.h"
|
|
#include "LaTeXFeatures.h"
|
|
#include "OutputParams.h"
|
|
#include "output_xhtml.h"
|
|
|
|
#include "support/docstream.h"
|
|
#include "support/FileName.h"
|
|
#include "support/filetools.h"
|
|
#include "support/gettext.h"
|
|
#include "support/lstrings.h"
|
|
|
|
#include "frontends/alert.h"
|
|
|
|
using namespace std;
|
|
using namespace lyx::support;
|
|
|
|
namespace lyx {
|
|
|
|
|
|
InsetHyperlink::InsetHyperlink(Buffer * buf, InsetCommandParams const & p)
|
|
: InsetCommand(buf, p)
|
|
{}
|
|
|
|
|
|
ParamInfo const & InsetHyperlink::findInfo(string const & /* cmdName */)
|
|
{
|
|
static ParamInfo param_info_;
|
|
if (param_info_.empty()) {
|
|
param_info_.add("name", ParamInfo::LATEX_OPTIONAL);
|
|
param_info_.add("target", ParamInfo::LATEX_REQUIRED);
|
|
param_info_.add("type", ParamInfo::LATEX_REQUIRED);
|
|
}
|
|
return param_info_;
|
|
}
|
|
|
|
|
|
docstring InsetHyperlink::screenLabel() const
|
|
{
|
|
docstring const temp = from_ascii("Hyperlink: ");
|
|
|
|
docstring url;
|
|
|
|
url += getParam("name");
|
|
if (url.empty())
|
|
url += getParam("target");
|
|
|
|
// elide if long
|
|
if (url.length() > 30) {
|
|
url = url.substr(0, 10) + "..."
|
|
+ url.substr(url.length() - 17, url.length());
|
|
}
|
|
return temp + url;
|
|
}
|
|
|
|
void InsetHyperlink::doDispatch(Cursor & cur, FuncRequest & cmd)
|
|
{
|
|
switch (cmd.action()) {
|
|
|
|
case LFUN_INSET_EDIT:
|
|
viewTarget();
|
|
break;
|
|
|
|
default:
|
|
InsetCommand::doDispatch(cur, cmd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
bool InsetHyperlink::getStatus(Cursor & cur, FuncRequest const & cmd,
|
|
FuncStatus & flag) const
|
|
{
|
|
switch (cmd.action()) {
|
|
case LFUN_INSET_EDIT:
|
|
flag.setEnabled(getParam("type").empty() || getParam("type") == "file:");
|
|
return true;
|
|
|
|
default:
|
|
return InsetCommand::getStatus(cur, cmd, flag);
|
|
}
|
|
}
|
|
|
|
|
|
void InsetHyperlink::viewTarget() const
|
|
{
|
|
if (getParam("type") == "file:") {
|
|
FileName url = makeAbsPath(to_utf8(getParam("target")), buffer().filePath());
|
|
string const format = formats.getFormatFromFile(url);
|
|
formats.view(buffer(), url, format);
|
|
}
|
|
}
|
|
|
|
|
|
void InsetHyperlink::latex(otexstream & os,
|
|
OutputParams const & runparams) const
|
|
{
|
|
docstring url = getParam("target");
|
|
docstring name = getParam("name");
|
|
static docstring const backslash = from_ascii("\\");
|
|
static docstring const braces = from_ascii("{}");
|
|
static char_type const chars_url[2] = {'%', '#'};
|
|
static char_type const chars_name[6] = {
|
|
'&', '_', '$', '%', '#', '^'};
|
|
|
|
// For the case there is no name given, the target is set as name.
|
|
// Do this before !url.empty() and !name.empty() to handle characters
|
|
// like the "%" correctly.
|
|
if (name.empty())
|
|
name = url;
|
|
|
|
if (!url.empty()) {
|
|
// Replace the "\" character by its ASCII code according to the
|
|
// URL specifications because "\" is not allowed in URLs and by
|
|
// \href. Only do this when the following character is not also
|
|
// a "\", because "\\" is valid code
|
|
for (size_t i = 0, pos;
|
|
(pos = url.find('\\', i)) != string::npos;
|
|
i = pos + 2) {
|
|
if (url[pos + 1] != '\\')
|
|
url.replace(pos, 1, from_ascii("%5C"));
|
|
}
|
|
|
|
// The characters in chars_url[] need to be escaped in the url
|
|
// field because otherwise LaTeX will fail when the hyperlink is
|
|
// within an argument of another command, e.g. in a \footnote. It
|
|
// is important that they are escaped as "\#" and not as "\#{}".
|
|
for (int k = 0; k < 2; k++)
|
|
for (size_t i = 0, pos;
|
|
(pos = url.find(chars_url[k], i)) != string::npos;
|
|
i = pos + 2)
|
|
url.replace(pos, 1, backslash + chars_url[k]);
|
|
|
|
// add "http://" when the type is web (type = empty)
|
|
// and no "://" or "run:" is given
|
|
docstring type = getParam("type");
|
|
if (url.find(from_ascii("://")) == string::npos
|
|
&& url.find(from_ascii("run:")) == string::npos
|
|
&& type.empty())
|
|
url = from_ascii("http://") + url;
|
|
|
|
} // end if (!url.empty())
|
|
|
|
// The characters in chars_name[] need to be changed to a command when
|
|
// they are in the name field.
|
|
if (!name.empty()) {
|
|
// handle the "\" character, but only when the following character
|
|
// is not also a "\", because "\\" is valid code
|
|
docstring const textbackslash = from_ascii("\\textbackslash{}");
|
|
for (size_t i = 0, pos;
|
|
(pos = name.find('\\', i)) != string::npos;
|
|
i = pos + 2) {
|
|
if (name[pos + 1] != '\\')
|
|
name.replace(pos, 1, textbackslash);
|
|
}
|
|
// The characters in chars_name[] need to be changed to a command
|
|
// when they are in the name field.
|
|
// Therefore the treatment of "\" must be the first thing
|
|
for (int k = 0; k < 6; k++)
|
|
for (size_t i = 0, pos;
|
|
(pos = name.find(chars_name[k], i)) != string::npos;
|
|
i = pos + 2)
|
|
name.replace(pos, 1, backslash + chars_name[k] + braces);
|
|
|
|
// replace the tilde by the \sim character as suggested in the
|
|
// LaTeX FAQ for URLs
|
|
docstring const sim = from_ascii("$\\sim$");
|
|
for (size_t i = 0, pos;
|
|
(pos = name.find('~', i)) != string::npos;
|
|
i = pos + 1)
|
|
name.replace(pos, 1, sim);
|
|
pair<docstring, docstring> name_latexed =
|
|
runparams.encoding->latexString(name, runparams.dryrun);
|
|
name = name_latexed.first;
|
|
if (!name_latexed.second.empty()) {
|
|
// issue a warning about omitted characters
|
|
// FIXME: should be passed to the error dialog
|
|
frontend::Alert::warning(_("Uncodable characters"),
|
|
bformat(_("The following characters that are used in the href inset are not\n"
|
|
"representable in the current encoding and therefore have been omitted:\n%1$s."),
|
|
name_latexed.second));
|
|
}
|
|
} // end if (!name.empty())
|
|
|
|
if (runparams.moving_arg)
|
|
os << "\\protect";
|
|
|
|
// output the ready \href command
|
|
os << "\\href{" << getParam("type") << url << "}{" << name << '}';
|
|
}
|
|
|
|
|
|
int InsetHyperlink::plaintext(odocstringstream & os,
|
|
OutputParams const &, size_t) const
|
|
{
|
|
odocstringstream oss;
|
|
|
|
oss << '[' << getParam("target");
|
|
if (getParam("name").empty())
|
|
oss << ']';
|
|
else
|
|
oss << "||" << getParam("name") << ']';
|
|
|
|
docstring const str = oss.str();
|
|
os << str;
|
|
return str.size();
|
|
}
|
|
|
|
|
|
int InsetHyperlink::docbook(odocstream & os, OutputParams const &) const
|
|
{
|
|
os << "<ulink url=\""
|
|
<< subst(getParam("target"), from_ascii("&"), from_ascii("&"))
|
|
<< "\">"
|
|
<< getParam("name")
|
|
<< "</ulink>";
|
|
return 0;
|
|
}
|
|
|
|
|
|
docstring InsetHyperlink::xhtml(XHTMLStream & xs, OutputParams const &) const
|
|
{
|
|
docstring const & target =
|
|
html::htmlize(getParam("target"), XHTMLStream::ESCAPE_AND);
|
|
docstring const & name = getParam("name");
|
|
xs << html::StartTag("a", to_utf8("href=\"" + target + "\""));
|
|
xs << (name.empty() ? target : name);
|
|
xs << html::EndTag("a");
|
|
return docstring();
|
|
}
|
|
|
|
|
|
void InsetHyperlink::toString(odocstream & os) const
|
|
{
|
|
odocstringstream ods;
|
|
plaintext(ods, OutputParams(0), INT_MAX);
|
|
os << ods.str();
|
|
}
|
|
|
|
|
|
void InsetHyperlink::forToc(docstring & os, size_t) const
|
|
{
|
|
docstring const & n = getParam("name");
|
|
if (!n.empty()) {
|
|
os += n;
|
|
return;
|
|
}
|
|
os += getParam("target");
|
|
}
|
|
|
|
|
|
docstring InsetHyperlink::toolTip(BufferView const & /*bv*/, int /*x*/, int /*y*/) const
|
|
{
|
|
docstring url = getParam("target");
|
|
docstring type = getParam("type");
|
|
docstring guitype = _("www");
|
|
if (type == "mailto:")
|
|
guitype = _("email");
|
|
else if (type == "file:")
|
|
guitype = _("file");
|
|
return bformat(_("Hyperlink (%1$s) to %2$s"), guitype, url);
|
|
}
|
|
|
|
|
|
void InsetHyperlink::validate(LaTeXFeatures & features) const
|
|
{
|
|
features.require("hyperref");
|
|
}
|
|
|
|
|
|
string InsetHyperlink::contextMenuName() const
|
|
{
|
|
return "context-hyperlink";
|
|
}
|
|
|
|
|
|
} // namespace lyx
|