commit e5ea53595239ef05a352e142ded5f4eed03a4fa0
Author: Richard Heck <[email protected]>
Date:   Sun Feb 23 11:20:47 2014 -0500

    If the selection is some sort of URL, then make it the target, not
    the name, in the hyperlink. Fixes bug #8792.
    
    This also fixes a bug discovered while working on this code: The
    params passed to GuiHyperlink were never used.

diff --git a/src/Text3.cpp b/src/Text3.cpp
index 1dead38..f54e8f4 100644
--- a/src/Text3.cpp
+++ b/src/Text3.cpp
@@ -73,6 +73,7 @@
 #include "support/lstrings.h"
 #include "support/lyxtime.h"
 #include "support/os.h"
+#include "support/regex.h"
 
 #include "mathed/InsetMathHull.h"
 #include "mathed/MathMacroTemplate.h"
@@ -1668,15 +1669,46 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        }
 
        case LFUN_HREF_INSERT: {
-               InsetCommandParams p(HYPERLINK_CODE);
-               docstring content;
+               // FIXME If we're actually given an argument, shouldn't
+               // we use it, whether or not we have a selection?
+               docstring content = cmd.argument();
                if (cur.selection()) {
                        content = cur.selectionAsString(false);
                        cutSelection(cur, true, false);
                }
-               p["target"] = (cmd.argument().empty()) ?
-                       content : cmd.argument();
+
+               InsetCommandParams p(HYPERLINK_CODE);
+               if (!content.empty()){
+                       // if it looks like a link, we'll put it as target,
+                       // otherwise as name (bug #8792).
+
+                       // We can't do:
+                       //   regex_match(to_utf8(content), matches, link_re)
+                       // because smatch stores pointers to the substrings 
rather
+                       // than making copies of them. And those pointers become
+                       // invalid after regex_match returns, since it is then
+                       // being given a temporary object. (Thanks to Georg for
+                       // figuring that out.)
+                       regex const link_re("^([a-zA-Z]+):.*");
+                       smatch matches;
+                       string const c = to_utf8(content);
+
+                       if (content.substr(0,7) == "mailto:";) {
+                               p["target"] = content;
+                               p["type"] = from_ascii("mailto:";);
+                       } else if (regex_match(c, matches, link_re)) {
+                               p["target"] = content;
+                               string protocol = matches.str(1);
+                               if (protocol == "file")
+                                       p["type"] = from_ascii("file:");
+                       } else
+                               p["name"] = content;
+               }
                string const data = InsetCommand::params2string(p);
+
+               // we need to have a target. if we already have one, then
+               // that gets used at the default for the name, too, which
+               // is probably what is wanted.
                if (p["target"].empty()) {
                        bv->showDialog("href", data);
                } else {
diff --git a/src/frontends/qt4/GuiHyperlink.cpp 
b/src/frontends/qt4/GuiHyperlink.cpp
index 7cb9cc6..6cd9262 100644
--- a/src/frontends/qt4/GuiHyperlink.cpp
+++ b/src/frontends/qt4/GuiHyperlink.cpp
@@ -68,6 +68,23 @@ void GuiHyperlink::paramsToDialog(Inset const * inset)
 }
 
 
+bool GuiHyperlink::initialiseParams(std::string const & data)
+{
+       InsetCommandParams params(insetCode());
+       if (!InsetCommand::string2params(data, params))
+               return false;
+       targetED->setText(toqstr(params["target"]));
+       nameED->setText(toqstr(params["name"]));
+       if (params["type"] == from_utf8("mailto:";))
+               emailRB->setChecked(true);
+       else if (params["type"] == from_utf8("file:"))
+               fileRB->setChecked(true);
+       else
+               webRB->setChecked(true);
+       return true;
+}
+
+
 docstring GuiHyperlink::dialogToParams() const
 {
        InsetCommandParams params(insetCode());
@@ -75,11 +92,11 @@ docstring GuiHyperlink::dialogToParams() const
        params["target"] = qstring_to_ucs4(targetED->text());
        params["name"] = qstring_to_ucs4(nameED->text());
        if (webRB->isChecked())
-               params["type"] = qstring_to_ucs4("");
+               params["type"] = from_utf8("");
        else if (emailRB->isChecked())
-               params["type"] = qstring_to_ucs4("mailto:";);
+               params["type"] = from_utf8("mailto:";);
        else if (fileRB->isChecked())
-               params["type"] = qstring_to_ucs4("file:");
+               params["type"] = from_utf8("file:");
        params.setCmdName("href");
        return from_utf8(InsetHyperlink::params2string(params));
 }
diff --git a/src/frontends/qt4/GuiHyperlink.h b/src/frontends/qt4/GuiHyperlink.h
index 2134ca8..d2dd0ee 100644
--- a/src/frontends/qt4/GuiHyperlink.h
+++ b/src/frontends/qt4/GuiHyperlink.h
@@ -35,6 +35,7 @@ private:
        void paramsToDialog(Inset const *);
        docstring dialogToParams() const;
        bool checkWidgets() const;
+       bool initialiseParams(std::string const & data);
        //@}
 };
 
diff --git a/src/support/lstrings.cpp b/src/support/lstrings.cpp
index dbf629c..2d483e6 100644
--- a/src/support/lstrings.cpp
+++ b/src/support/lstrings.cpp
@@ -481,6 +481,14 @@ docstring const lowercase(docstring const & a)
 }
 
 
+string const lowercase(string const & a)
+{
+       string tmp(a);
+       transform(tmp.begin(), tmp.end(), tmp.begin(), local_lowercase());
+       return tmp;
+}
+
+
 docstring const uppercase(docstring const & a)
 {
        docstring tmp(a);
diff --git a/src/support/lstrings.h b/src/support/lstrings.h
index 2606546..89450c7 100644
--- a/src/support/lstrings.h
+++ b/src/support/lstrings.h
@@ -96,6 +96,7 @@ docstring const ascii_lowercase(docstring const &);
 
 /// Changes the case of \p s to lowercase.
 /// Does not depend on the locale.
+std::string const lowercase(std::string const & s);
 docstring const lowercase(docstring const & s);
 
 /// Changes the case of \p s to uppercase.

Reply via email to