1 /*
2  * urlobject.cpp - helper class for handling links
3  * Copyright (C) 2003-2006  Michail Pishchagin
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  */
20 
21 #include "urlobject.h"
22 #include "psioptions.h"
23 
24 #include <QApplication>
25 #include <QClipboard>
26 #include <QMenu>
27 #include <QSignalMapper>
28 #include <QUrl>
29 #ifdef HAVE_QT5
30 # include <QUrlQuery>
31 #endif
32 
33 #include "iconaction.h"
34 
35 //! \if _hide_doc_
36 class URLObject::Private : QObject
37 {
38 	Q_OBJECT
39 public:
40 	QString link;
41 	IconAction *act_xmpp, *act_mailto, *act_join_groupchat, *act_send_message, *act_chat, *act_browser, *act_add_to_roster, *act_copy, *act_info;
42 	URLObject *urlObject;
43 	QSignalMapper xmppActionMapper;
44 
connectXmppAction(QAction * action,const QString & query)45 	void connectXmppAction(QAction* action, const QString& query)
46 	{
47 		connect(action, SIGNAL(triggered()), &xmppActionMapper, SLOT(map()));
48 		xmppActionMapper.setMapping(action, query);
49 	}
50 
Private(URLObject * parent)51 	Private(URLObject *parent)
52 		: QObject(parent)
53 	{
54 		urlObject = parent;
55 		QString tr;
56 
57 		tr = qApp->translate("URLLabel", "Open");
58 		act_xmpp = new IconAction(tr, "psi/jabber", tr, 0, this);
59 		connectXmppAction(act_xmpp, "");
60 
61 		tr = qApp->translate("URLLabel", "Open mail composer");
62 		act_mailto = new IconAction(tr, "psi/email", tr, 0, this);
63 		connect(act_mailto, SIGNAL(triggered()), SLOT(popupAction()));
64 
65 		tr = qApp->translate("URLLabel", "Open web browser");
66 		act_browser = new IconAction(tr, "psi/www", tr, 0, this);
67 		connect(act_browser, SIGNAL(triggered()), SLOT(popupAction()));
68 
69 		tr = qApp->translate("URLLabel", "Add to Roster");
70 		act_add_to_roster = new IconAction(tr, "psi/addContact", tr, 0, this);
71 		connectXmppAction(act_add_to_roster, "roster");
72 
73 		tr = qApp->translate("URLLabel", "Send message to");
74 		act_send_message = new IconAction(tr, "psi/message", tr, 0, this);
75 		connectXmppAction(act_send_message, "message");
76 
77 		tr = qApp->translate("URLLabel", "Chat with");
78 		act_chat = new IconAction(tr, "psi/chat", tr, 0, this);
79 		connectXmppAction(act_chat, "message;type=chat");
80 
81 		tr = qApp->translate("URLLabel", "Join groupchat");
82 		act_join_groupchat = new IconAction(tr, "psi/groupChat", tr, 0, this);
83 		connectXmppAction(act_join_groupchat, "join");
84 
85 		tr = qApp->translate("URLLabel", "Copy location");
86 		act_copy = new IconAction(tr, tr, 0, this);
87 		connect(act_copy, SIGNAL(triggered()), SLOT(popupCopy()));
88 
89 		tr = qApp->translate("URLLabel", "User Info");
90 		act_info = new IconAction(tr, "psi/vCard", tr, 0, this);
91 		connectXmppAction(act_info, "vcard");
92 
93 		connect(&xmppActionMapper, SIGNAL(mapped(const QString&)), SLOT(xmppAction(const QString&)));
94 	}
95 
copyString(QString from)96 	QString copyString(QString from)
97 	{
98 		QString l = from;
99 
100 		int colon = l.indexOf(':');
101 		if ( colon == -1 )
102 			colon = 0;
103 		QString service = l.left( colon );
104 
105 		if ( service == "mailto" || service == "jabber" || service == "jid" || service == "xmpp" || service == "x-psi-atstyle") {
106 			if ( colon > -1 )
107 				l = l.mid( colon + 1 );
108 
109 			while ( l[0] == '/' )
110 				l = l.mid( 1 );
111 		}
112 
113 		return l;
114 	}
115 
116 public slots:
popupAction(QString lnk)117 	void popupAction(QString lnk) {
118 		if (lnk.startsWith("x-psi-atstyle:")) {
119 			lnk.replace(0, 13, "mailto");
120 		}
121 		emit urlObject->openURL(lnk);
122 	}
123 
popupAction()124 	void popupAction() {
125 		popupAction(link);
126 	}
127 
popupCopy(QString lnk)128 	void popupCopy(QString lnk) {
129 		QApplication::clipboard()->setText( copyString(lnk), QClipboard::Clipboard );
130 		if(QApplication::clipboard()->supportsSelection())
131 			QApplication::clipboard()->setText( copyString(lnk), QClipboard::Selection );
132 	}
133 
popupCopy()134 	void popupCopy() {
135 		popupCopy(link);
136 	}
137 
xmppAction(const QString & lnk,const QString & query)138 	void xmppAction(const QString& lnk, const QString& query) {
139 		QUrl uri(lnk);
140 		if (!query.isEmpty()) {
141 			QString queryType = query.left(query.indexOf(';'));
142 #ifdef HAVE_QT5
143 			QUrlQuery q;
144 			q.setQueryDelimiters('=', ';');
145 			q.setQuery(uri.query(QUrl::FullyEncoded));
146 
147 			if (q.queryItems().value(0).first != queryType) {
148 				q.setQuery(query);
149 			}
150 			uri.setQuery(q);
151 #else
152 			uri.setQueryDelimiters('=', ';');
153 			if (uri.queryItems().value(0).first != queryType) {
154 				uri.setEncodedQuery(query.toLatin1());
155 			}
156 #endif
157 		}
158 		uri.setScheme("xmpp");
159 		emit urlObject->openURL(uri.toString());
160 	}
161 
xmppAction(const QString & query)162 	void xmppAction(const QString& query) {
163 		xmppAction(link, query);
164 	}
165 };
166 //! \endif
167 
168 /**
169  * \class URLObject
170  * \brief Helper class for handling clicking on URLs
171  */
172 
173 /**
174  * Default constructor.
175  */
URLObject()176 URLObject::URLObject()
177 	: QObject(qApp)
178 {
179 	d = new Private(this);
180 }
181 
182 /**
183  * Returns instance of the class, and creates it if necessary.
184  */
getInstance()185 URLObject *URLObject::getInstance()
186 {
187 	static URLObject *urlObject = 0;
188 	if (!urlObject)
189 		urlObject = new URLObject();
190 	return urlObject;
191 }
192 
193 /**
194  * Creates QMenu with actions corresponding to link's type.
195  * @param lnk link in service:url format
196  */
createPopupMenu(const QString & lnk)197 QMenu *URLObject::createPopupMenu(const QString &lnk)
198 {
199 	d->link = lnk;
200 	if ( d->link.isEmpty() )
201 		return 0;
202 
203 	int colon = d->link.indexOf(':');
204 	if ( colon == -1 )
205 		colon = 0;
206 	QString service = d->link.left( colon );
207 
208 	QMenu *m = new QMenu;
209 
210 	bool needGenericOpen = true;
211 	if (service == "mailto" || service == "x-psi-atstyle") {
212 		needGenericOpen = false;
213 		m->addAction(d->act_mailto);
214 	}
215 	if (service == "jabber" || service == "jid" || service == "xmpp" || service == "x-psi-atstyle") {
216 		needGenericOpen = false;
217 		if (service == "x-psi-atstyle") {
218 			m->addSeparator();
219 		}
220 		m->addAction(d->act_info);
221 		m->addAction(d->act_xmpp);
222 		m->addAction(d->act_chat);
223 		m->addAction(d->act_send_message);
224 		m->addAction(d->act_join_groupchat);
225 		//m->addAction(d->act_add_to_roster);
226 		if (service == "x-psi-atstyle") {
227 			m->addSeparator();
228 		}
229 	}
230 	if (needGenericOpen) {
231 		m->addAction(d->act_browser);
232 	}
233 
234 	m->addAction(d->act_copy);
235 	m->setStyleSheet(PsiOptions::instance()->getOption("options.ui.look.css").toString());
236 	return m;
237 }
238 
239 /**
240  * Simulates default action using the passed URL.
241  * \param lnk URL string
242  */
popupAction(QString lnk)243 void URLObject::popupAction(QString lnk)
244 {
245 	d->popupAction(lnk);
246 }
247 
248 #include "urlobject.moc"
249