Back to index

lightning-sunbird  0.9+nobinonly
nsMaiHyperlink.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  *
00008  * The contents of this file are subject to the Mozilla Public
00009  * License Version 1.1 (the "License"); you may not use this file
00010  * except in compliance with the License. You may obtain a copy of
00011  * the License at http://www.mozilla.org/MPL/
00012  *
00013  * Software distributed under the License is distributed on an "AS
00014  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00015  * implied. See the License for the specific language governing
00016  * rights and limitations under the License.
00017  *
00018  * The Original Code is mozilla.org code.
00019  *
00020  * The Initial Developer of the Original Code is Sun Microsystems, Inc.
00021  * Portions created by Sun Microsystems are Copyright (C) 2002 Sun
00022  * Microsystems, Inc. All Rights Reserved.
00023  *
00024  * Original Author: Bolian Yin (bolian.yin@sun.com)
00025  *
00026  * Contributor(s): 
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the NPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the NPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsIURI.h"
00043 #include "nsMaiHyperlink.h"
00044 
00045 /* MaiAtkHyperlink */
00046 
00047 #define MAI_TYPE_ATK_HYPERLINK      (mai_atk_hyperlink_get_type ())
00048 #define MAI_ATK_HYPERLINK(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
00049                                      MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlink))
00050 #define MAI_ATK_HYPERLINK_CLASS(klass)  (G_TYPE_CHECK_CLASS_CAST ((klass),\
00051                                  MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass))
00052 #define MAI_IS_ATK_HYPERLINK(obj)      (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
00053                                         MAI_TYPE_ATK_HYPERLINK))
00054 #define MAI_IS_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
00055                                         MAI_TYPE_ATK_HYPERLINK))
00056 #define MAI_ATK_HYPERLINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
00057                                  MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass))
00058 
00064 struct MaiAtkHyperlink
00065 {
00066     AtkHyperlink parent;
00067 
00068     /*
00069      * The MaiHyperlink whose properties and features are exported via this
00070      * hyperlink instance.
00071      */
00072     MaiHyperlink *maiHyperlink;
00073     gchar *uri;
00074 };
00075 
00076 struct MaiAtkHyperlinkClass
00077 {
00078     AtkHyperlinkClass parent_class;
00079 };
00080 
00081 GType mai_atk_hyperlink_get_type(void);
00082 
00083 G_BEGIN_DECLS
00084 /* callbacks for AtkHyperlink */
00085 static void classInitCB(AtkHyperlinkClass *aClass);
00086 static void finalizeCB(GObject *aObj);
00087 
00088 /* callbacks for AtkHyperlink virtual functions */
00089 static gchar *getUriCB(AtkHyperlink *aLink, gint aLinkIndex);
00090 static AtkObject *getObjectCB(AtkHyperlink *aLink, gint aLinkIndex);
00091 static gint getEndIndexCB(AtkHyperlink *aLink);
00092 static gint getStartIndexCB(AtkHyperlink *aLink);
00093 static gboolean isValidCB(AtkHyperlink *aLink);
00094 static gint getAnchorCountCB(AtkHyperlink *aLink);
00095 G_END_DECLS
00096 
00097 static gpointer parent_class = NULL;
00098 static nsIAccessibleHyperLink *
00099 get_accessible_hyperlink(AtkHyperlink *aHyperlink);
00100 
00101 GType
00102 mai_atk_hyperlink_get_type(void)
00103 {
00104     static GType type = 0;
00105 
00106     if (!type) {
00107         static const GTypeInfo tinfo = {
00108             sizeof(MaiAtkHyperlinkClass),
00109             (GBaseInitFunc)NULL,
00110             (GBaseFinalizeFunc)NULL,
00111             (GClassInitFunc)classInitCB,
00112             (GClassFinalizeFunc)NULL,
00113             NULL, /* class data */
00114             sizeof(MaiAtkHyperlink), /* instance size */
00115             0, /* nb preallocs */
00116             (GInstanceInitFunc)NULL,
00117             NULL /* value table */
00118         };
00119 
00120         type = g_type_register_static(ATK_TYPE_HYPERLINK,
00121                                       "MaiAtkHyperlink",
00122                                       &tinfo, GTypeFlags(0));
00123     }
00124     return type;
00125 }
00126 
00127 MaiHyperlink::MaiHyperlink(nsIAccessibleHyperLink *aAcc,
00128                            nsIDOMNode *aNode, nsIWeakReference* aShell):
00129     nsAccessNodeWrap(aNode, aShell),
00130     mHyperlink(aAcc),
00131     mMaiAtkHyperlink(nsnull)
00132 {
00133 }
00134 
00135 MaiHyperlink::~MaiHyperlink()
00136 {
00137     if (mMaiAtkHyperlink)
00138         g_object_unref(mMaiAtkHyperlink);
00139 }
00140 
00141 // MaiHyperlink use its nsIAccessibleHyperlink raw pointer as ID
00142 NS_IMETHODIMP MaiHyperlink::GetUniqueID(void **aUniqueID)
00143 {
00144     if (!mHyperlink)
00145         return NS_ERROR_FAILURE;
00146     *aUniqueID = NS_STATIC_CAST(void*, mHyperlink.get());
00147     return NS_OK;
00148 }
00149 
00150 AtkHyperlink *
00151 MaiHyperlink::GetAtkHyperlink(void)
00152 {
00153     NS_ENSURE_TRUE(mHyperlink, nsnull);
00154 
00155     if (mMaiAtkHyperlink)
00156         return mMaiAtkHyperlink;
00157 
00158     nsCOMPtr<nsIAccessibleHyperLink> accessIf(do_QueryInterface(mHyperlink));
00159     if (!accessIf)
00160         return nsnull;
00161 
00162     mMaiAtkHyperlink =
00163         NS_REINTERPRET_CAST(AtkHyperlink *,
00164                             g_object_new(mai_atk_hyperlink_get_type(), NULL));
00165     NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY");
00166     NS_ENSURE_TRUE(mMaiAtkHyperlink, nsnull);
00167 
00168     /* be sure to initialize it with "this" */
00169     MaiHyperlink::Initialize(mMaiAtkHyperlink, this);
00170 
00171     return mMaiAtkHyperlink;
00172 }
00173 
00174 /* static */
00175 
00176 /* remember to call this static function when a MaiAtkHyperlink
00177  * is created
00178  */
00179 
00180 nsresult
00181 MaiHyperlink::Initialize(AtkHyperlink *aObj, MaiHyperlink *aHyperlink)
00182 {
00183     NS_ENSURE_ARG(MAI_IS_ATK_HYPERLINK(aObj));
00184     NS_ENSURE_ARG(aHyperlink);
00185 
00186     /* initialize hyperlink */
00187     MAI_ATK_HYPERLINK(aObj)->maiHyperlink = aHyperlink;
00188     MAI_ATK_HYPERLINK(aObj)->uri = nsnull;
00189     return NS_OK;
00190 }
00191 
00192 /* static functions for ATK callbacks */
00193 
00194 void
00195 classInitCB(AtkHyperlinkClass *aClass)
00196 {
00197     GObjectClass *gobject_class = G_OBJECT_CLASS(aClass);
00198 
00199     parent_class = g_type_class_peek_parent(aClass);
00200 
00201     aClass->get_uri = getUriCB;
00202     aClass->get_object = getObjectCB;
00203     aClass->get_end_index = getEndIndexCB;
00204     aClass->get_start_index = getStartIndexCB;
00205     aClass->is_valid = isValidCB;
00206     aClass->get_n_anchors = getAnchorCountCB;
00207 
00208     gobject_class->finalize = finalizeCB;
00209 }
00210 
00211 void
00212 finalizeCB(GObject *aObj)
00213 {
00214     NS_ASSERTION(MAI_IS_ATK_HYPERLINK(aObj), "Invalid MaiAtkHyperlink");
00215     if (!MAI_IS_ATK_HYPERLINK(aObj))
00216         return;
00217 
00218     MaiAtkHyperlink *maiHyperlink = MAI_ATK_HYPERLINK(aObj);
00219     if (maiHyperlink->uri)
00220         g_free(maiHyperlink->uri);
00221     maiHyperlink->maiHyperlink = nsnull;
00222 
00223     /* call parent finalize function */
00224     if (G_OBJECT_CLASS (parent_class)->finalize)
00225         G_OBJECT_CLASS (parent_class)->finalize(aObj);
00226 }
00227 
00228 gchar *
00229 getUriCB(AtkHyperlink *aLink, gint aLinkIndex)
00230 {
00231     nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink);
00232     NS_ENSURE_TRUE(accHyperlink, nsnull);
00233 
00234     MaiAtkHyperlink *maiHyperlink = MAI_ATK_HYPERLINK(accHyperlink);
00235     if (maiHyperlink->uri)
00236         return maiHyperlink->uri;
00237 
00238     nsCOMPtr<nsIURI> uri;
00239     nsresult rv = accHyperlink->GetURI(aLinkIndex,getter_AddRefs(uri));
00240     if (NS_FAILED(rv) || !uri)
00241         return nsnull;
00242     nsCAutoString cautoStr;
00243     rv = uri->GetSpec(cautoStr);
00244 
00245     maiHyperlink->uri = g_strdup(cautoStr.get());
00246     return maiHyperlink->uri;
00247 }
00248 
00249 AtkObject *
00250 getObjectCB(AtkHyperlink *aLink, gint aLinkIndex)
00251 {
00252     nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink);
00253     NS_ENSURE_TRUE(accHyperlink, nsnull);
00254 
00255     nsCOMPtr<nsIAccessible> accObj;
00256     nsresult rv = accHyperlink->GetObject(aLinkIndex, getter_AddRefs(accObj));
00257     NS_ENSURE_SUCCESS(rv, nsnull);
00258     AtkObject *atkObj = nsnull;
00259     if (accObj) {
00260         nsIAccessible *tmpObj = accObj;
00261         nsAccessibleWrap *accWrap = NS_STATIC_CAST(nsAccessibleWrap *, tmpObj);
00262         atkObj = accWrap->GetAtkObject();
00263     }
00264     //no need to add ref it, because it is "get" not "ref" ???
00265     return atkObj;
00266 }
00267 
00268 gint
00269 getEndIndexCB(AtkHyperlink *aLink)
00270 {
00271     nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink);
00272     NS_ENSURE_TRUE(accHyperlink, -1);
00273 
00274     PRInt32 endIndex = -1;
00275     nsresult rv = accHyperlink->GetEndIndex(&endIndex);
00276 
00277     return (NS_FAILED(rv)) ? -1 : NS_STATIC_CAST(gint, endIndex);
00278 }
00279 
00280 gint
00281 getStartIndexCB(AtkHyperlink *aLink)
00282 {
00283     nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink);
00284     NS_ENSURE_TRUE(accHyperlink, -1);
00285 
00286     PRInt32 startIndex = -1;
00287     nsresult rv = accHyperlink->GetStartIndex(&startIndex);
00288 
00289     return (NS_FAILED(rv)) ? -1 : NS_STATIC_CAST(gint, startIndex);
00290 }
00291 
00292 gboolean
00293 isValidCB(AtkHyperlink *aLink)
00294 {
00295     nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink);
00296     NS_ENSURE_TRUE(accHyperlink, FALSE);
00297 
00298     PRBool isValid = PR_FALSE;
00299     nsresult rv = accHyperlink->IsValid(&isValid);
00300     return (NS_FAILED(rv)) ? FALSE : NS_STATIC_CAST(gboolean, isValid);
00301 }
00302 
00303 gint
00304 getAnchorCountCB(AtkHyperlink *aLink)
00305 {
00306     nsIAccessibleHyperLink *accHyperlink = get_accessible_hyperlink(aLink);
00307     NS_ENSURE_TRUE(accHyperlink, -1);
00308 
00309     PRInt32 count = -1;
00310     nsresult rv = accHyperlink->GetAnchors(&count);
00311     return (NS_FAILED(rv)) ? -1 : NS_STATIC_CAST(gint, count);
00312 }
00313 
00314 // Check if aHyperlink is a valid MaiHyperlink, and return the
00315 // nsIAccessibleHyperLink related.
00316 nsIAccessibleHyperLink *
00317 get_accessible_hyperlink(AtkHyperlink *aHyperlink)
00318 {
00319     NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink), nsnull);
00320     MaiHyperlink * maiHyperlink =
00321         MAI_ATK_HYPERLINK(aHyperlink)->maiHyperlink;
00322     NS_ENSURE_TRUE(maiHyperlink != nsnull, nsnull);
00323     NS_ENSURE_TRUE(maiHyperlink->GetAtkHyperlink() == aHyperlink, nsnull);
00324     return maiHyperlink->GetAccHyperlink();
00325 }