1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent tw=79 ft=cpp: */
4 * Copyright (C) 2007,2008 Sergey Yanovich <ynvich@gmail.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 #include "xpcom-config.h"
24 #include "nsStringAPI.h"
25 #include "nsIDOMElement.h"
26 #include "nsIDOMNode.h"
27 #include "nsIDOMDocument.h"
28 #include "nsIDOMXULElement.h"
29 #include "nsIInterfaceRequestorUtils.h"
30 #include "nsISHistory.h"
31 #include "nsServiceManagerUtils.h"
32 #include "nsIObserverService.h"
33 #include "nsComponentManagerUtils.h"
36 #include "nsITreeSelection.h"
37 #include "nsITreeColumns.h"
38 #include "nsITreeBoxObject.h"
40 #include "nsArrayUtils.h"
41 #include "nsClassHashtable.h"
43 /* Project includes */
44 #include "aaTreeView.h"
45 #include "aaISession.h"
46 #include "aaISqlTransaction.h"
47 #include "aaISqlRequest.h"
48 #include "aaBaseLoaders.h"
50 #include "aaIOrderCondition.h"
51 #include "aaIFilterCondition.h"
52 #include "aaConditionKeys.h"
53 #include "aaISqlFilter.h"
55 /*******************************************************************/
56 class CTreeViewFilters
: public aaITreeViewFilters
62 CTreeViewFilter(nsITreeColumn
* col
, const nsAString
& param
)
70 NS_IMETHOD
GetColumn(nsITreeColumn
** col
) {
71 NS_ENSURE_ARG_POINTER(col
);
72 NS_IF_ADDREF(*col
= mColumn
);
75 NS_IMETHOD
GetParam(nsAString
& param
) {
81 nsCOMPtr
<nsITreeColumn
> mColumn
;
87 NS_DECL_AAITREEVIEWFILTERS
91 typedef nsClassHashtable
<nsUint32HashKey
, CTreeViewFilter
> aaFilterHashtable
;
92 aaFilterHashtable mContainer
;
95 NS_IMPL_ISUPPORTS1(CTreeViewFilters
, aaITreeViewFilters
)
97 CTreeViewFilters::CTreeViewFilters() {
101 CTreeViewFilters::~CTreeViewFilters() {
105 CTreeViewFilters::AddFilter(PRInt16 type
, nsITreeColumn
* col
, const nsAString
& param
)
107 NS_ENSURE_ARG_POINTER(col
);
108 if (!mContainer
.Put(PRUint32(type
), new CTreeViewFilter(col
, param
))) {
109 return NS_ERROR_FAILURE
;
115 CTreeViewFilters::Clear()
121 PLDHashOperator
EnumFunc(const PRUint32
& type
, nsAutoPtr
<CTreeViewFilters::CTreeViewFilter
>& filter
, void* userArg
)
123 if (nsnull
!= userArg
) {
124 nsCOMPtr
<nsITreeColumn
> col
;
126 aaITreeFilterObserver
* pObserver
= (aaITreeFilterObserver
*)userArg
;
127 if (NS_SUCCEEDED(filter
->GetColumn(getter_AddRefs(col
))) && NS_SUCCEEDED(filter
->GetParam(param
))) {
128 PRBool moveNext
= PR_TRUE
;
129 if (NS_SUCCEEDED(pObserver
->Next(PRInt16(type
), col
, param
, &moveNext
))) {
130 return moveNext
? PL_DHASH_NEXT
: PL_DHASH_STOP
;
134 return PL_DHASH_STOP
;
138 CTreeViewFilters::Observe(aaITreeFilterObserver
*observer
)
140 NS_ENSURE_ARG_POINTER(observer
);
141 mContainer
.Enumerate((aaFilterHashtable::EnumFunction
)&EnumFunc
, observer
);
146 CTreeViewFilters::IsExist(PRInt16 type
, PRBool
*_retval NS_OUTPARAM
)
149 NS_ENSURE_ARG_POINTER(_retval
);
151 CTreeViewFilter
* pFilter
= nsnull
;
152 if (mContainer
.Get(type
, &pFilter
)) {
159 CTreeViewFilters::GetFilter(PRInt16 type
, nsITreeColumn
**col NS_OUTPARAM
, nsAString
& param NS_OUTPARAM
)
162 CTreeViewFilter
* pFilter
= nsnull
;
163 NS_ENSURE_ARG_POINTER(col
);
164 if (!mContainer
.Get(type
, &pFilter
)) {
165 return NS_ERROR_INVALID_ARG
;
168 NS_ENSURE_SUCCESS(rc
= pFilter
->GetColumn(col
), rc
);
169 NS_ENSURE_SUCCESS(rc
= pFilter
->GetParam(param
), rc
);
172 /*******************************************************************/
174 aaTreeView::aaTreeView()
181 aaTreeView::~aaTreeView()
186 aaTreeView::Init(nsISupports
*aParam
)
189 mSession
= do_QueryInterface(aParam
, &rv
);
190 NS_ENSURE_SUCCESS(rv
, rv
);
195 NS_IMPL_ISUPPORTS3(aaTreeView
,
198 aaITreeFilterObserver
)
201 aaTreeView::GetRowCount(PRInt32
*aRowCount
)
203 NS_ENSURE_ARG_POINTER(aRowCount
);
208 return mDataSet
->GetLength((PRUint32
*) aRowCount
);
212 aaTreeView::GetSelection(nsITreeSelection
* *aSelection
)
214 NS_ENSURE_ARG_POINTER( aSelection
);
215 NS_IF_ADDREF(*aSelection
= mSelection
);
219 aaTreeView::SetSelection(nsITreeSelection
* aSelection
)
221 mSelection
= aSelection
;
227 aaTreeView::GetRowProperties(PRInt32 index
, nsISupportsArray
*properties
)
229 return NS_ERROR_NOT_IMPLEMENTED
;
233 aaTreeView::GetCellProperties(PRInt32 row
, nsITreeColumn
*col
, nsISupportsArray
*properties
)
235 return NS_ERROR_NOT_IMPLEMENTED
;
239 aaTreeView::GetColumnProperties(nsITreeColumn
*col
, nsISupportsArray
*properties
)
241 return NS_ERROR_NOT_IMPLEMENTED
;
245 aaTreeView::IsContainer(PRInt32 index
, PRBool
*_retval
)
247 NS_ENSURE_ARG_POINTER(_retval
);
253 aaTreeView::IsContainerOpen(PRInt32 index
, PRBool
*_retval
)
255 return NS_ERROR_NOT_IMPLEMENTED
;
259 aaTreeView::IsContainerEmpty(PRInt32 index
, PRBool
*_retval
)
261 return NS_ERROR_NOT_IMPLEMENTED
;
265 aaTreeView::IsSeparator(PRInt32 index
, PRBool
*_retval
)
267 NS_ENSURE_ARG_POINTER(_retval
);
273 aaTreeView::IsSorted(PRBool
*_retval
)
275 return NS_ERROR_NOT_IMPLEMENTED
;
279 aaTreeView::CanDrop(PRInt32 index
, PRInt32 orientation
,
280 nsIDOMDataTransfer
*dataTransfer
, PRBool
*_retval NS_OUTPARAM
)
282 return NS_ERROR_NOT_IMPLEMENTED
;
286 aaTreeView::Drop(PRInt32 row
, PRInt32 orientation
,
287 nsIDOMDataTransfer
*dataTransfer
)
289 return NS_ERROR_NOT_IMPLEMENTED
;
293 aaTreeView::GetParentIndex(PRInt32 rowIndex
, PRInt32
*_retval
)
295 return NS_ERROR_NOT_IMPLEMENTED
;
299 aaTreeView::HasNextSibling(PRInt32 rowIndex
, PRInt32 afterIndex
, PRBool
*_retval
)
301 NS_ENSURE_ARG_POINTER(_retval
);
304 rv
= GetRowCount(&count
);
305 NS_ENSURE_SUCCESS(rv
, rv
);
306 if (rowIndex
== afterIndex
&& rowIndex
< count
) {
315 aaTreeView::GetLevel(PRInt32 index
, PRInt32
*_retval
)
317 NS_ENSURE_ARG_POINTER(_retval
);
323 aaTreeView::GetImageSrc(PRInt32 row
, nsITreeColumn
*col
, nsAString
& _retval
)
325 return NS_ERROR_NOT_IMPLEMENTED
;
329 aaTreeView::GetProgressMode(PRInt32 row
, nsITreeColumn
*col
, PRInt32
*_retval
)
331 return NS_ERROR_NOT_IMPLEMENTED
;
335 aaTreeView::GetCellValue(PRInt32 row
, nsITreeColumn
*col
, nsAString
& _retval
)
337 return NS_ERROR_NOT_IMPLEMENTED
;
341 aaTreeView::GetCellText(PRInt32 row
, nsITreeColumn
*col
, nsAString
& _retval
)
344 * There may be a bug in <tree> implementation. This function is
345 * occasionally called after mTree is detached by SetTree(nsnull);
347 NS_ENSURE_TRUE(mDataSet
, NS_ERROR_NOT_INITIALIZED
);
348 NS_ENSURE_TRUE(row
>= 0, NS_ERROR_INVALID_ARG
);
349 return doGetCellText(row
, col
, _retval
);
353 aaTreeView::SetTree(nsITreeBoxObject
*tree
)
360 aaTreeView::ToggleOpenState(PRInt32 index
)
362 return NS_ERROR_NOT_IMPLEMENTED
;
366 aaTreeView::CycleHeader(nsITreeColumn
*col
)
368 //when column clicked, method was called by treecol handler
369 return NS_OK
;//NS_ERROR_NOT_IMPLEMENTED;
373 aaTreeView::SelectionChanged()
379 aaTreeView::CycleCell(PRInt32 row
, nsITreeColumn
*col
)
381 return NS_ERROR_NOT_IMPLEMENTED
;
385 aaTreeView::IsEditable(PRInt32 row
, nsITreeColumn
*col
, PRBool
*_retval
)
387 return NS_ERROR_NOT_IMPLEMENTED
;
391 aaTreeView::IsSelectable(PRInt32 row
, nsITreeColumn
*col
, PRBool
*_retval
)
393 NS_ENSURE_ARG_POINTER(_retval
);
399 aaTreeView::SetCellValue(PRInt32 row
, nsITreeColumn
*col
, const nsAString
& value
)
401 return NS_ERROR_NOT_IMPLEMENTED
;
405 aaTreeView::SetCellText(PRInt32 row
, nsITreeColumn
*col
, const nsAString
& value
)
407 return NS_ERROR_NOT_IMPLEMENTED
;
411 aaTreeView::PerformAction(const PRUnichar
*action
)
413 return NS_ERROR_NOT_IMPLEMENTED
;
417 aaTreeView::PerformActionOnRow(const PRUnichar
*action
, PRInt32 row
)
419 return NS_ERROR_NOT_IMPLEMENTED
;
423 aaTreeView::PerformActionOnCell(const PRUnichar
*action
, PRInt32 row
, nsITreeColumn
*col
)
425 return NS_ERROR_NOT_IMPLEMENTED
;
428 /* aaIDataTreeView */
430 aaTreeView::GetDataSet(nsIArray
* * aDataSet
)
432 NS_ENSURE_ARG_POINTER(aDataSet
);
433 NS_IF_ADDREF(*aDataSet
= mDataSet
);
437 NS_IMETHODIMP
aaTreeView::GetOldRowCount(PRInt32
* aRowCount
) {
438 *aRowCount
= mOldRowCount
;
442 NS_IMETHODIMP
aaTreeView::RowCountChanged(PRInt32 aOldRowCount
, PRInt32 aNewRowCount
) {
443 if (mOldRowCount
== aOldRowCount
) {
444 mOldRowCount
= aNewRowCount
;
447 return NS_ERROR_INVALID_ARG
;
451 aaTreeView::Update(nsISupports
*aParam
= 0)
453 NS_ENSURE_TRUE(mDataLoader
|| mComplexLoader
, NS_ERROR_NOT_INITIALIZED
);
455 PRInt32 oldCount
= 0;
456 PRInt32 newRowCount
= 0;
459 rv
= GetOldRowCount(&oldCount
);
460 NS_ENSURE_SUCCESS(rv
, rv
);
463 mTree
->RowCountChanged(0, - oldCount
);
466 rv
= buildFilter(aParam
);
467 NS_ENSURE_SUCCESS(rv
, rv
);
470 rv
= mDataLoader
->SetFilter(mFilter
);
471 NS_ENSURE_SUCCESS(rv
, rv
);
473 rv
= mSession
->Load(mDataLoader
, getter_AddRefs(mDataSet
));
474 NS_ENSURE_SUCCESS(rv
, rv
);
476 rv
= postLoadHandler();
477 NS_ENSURE_SUCCESS(rv
, rv
);
480 nsCOMPtr
<nsISupports
> supReturn
;
482 rv
= mComplexLoader
->SetParam(mFilter
);
483 NS_ENSURE_SUCCESS(rv
, rv
);
485 rv
= mSession
->Execute(mComplexLoader
, getter_AddRefs(supReturn
));
486 NS_ENSURE_SUCCESS(rv
, rv
);
487 NS_ENSURE_TRUE(supReturn
, NS_ERROR_UNEXPECTED
);
489 rv
= supReturn
->QueryInterface(NS_GET_IID(nsIArray
), getter_AddRefs(mDataSet
));
490 NS_ENSURE_SUCCESS(rv
, rv
);
493 rv
= GetRowCount(&newRowCount
);
494 NS_ENSURE_SUCCESS(rv
, rv
);
496 rv
= RowCountChanged(oldCount
, newRowCount
);
497 NS_ENSURE_SUCCESS(rv
, rv
);
500 mTree
->RowCountChanged(0, newRowCount
);
503 nsCOMPtr
<nsIObserverService
> broadcaster
= do_GetService("@mozilla.org/observer-service;1");
504 NS_ENSURE_TRUE(broadcaster
, NS_OK
);
505 broadcaster
->NotifyObservers(reinterpret_cast<nsISupports
*>(this), "tree-view-load", nsnull
);
507 rv
= dataLoadSuccess();
508 NS_ENSURE_SUCCESS(rv
, rv
);
514 aaTreeView::GetFlags(PRUint32
*aFlags
)
516 NS_ENSURE_ARG_POINTER(aFlags
);
521 aaTreeView::SetFlags(PRUint32 aFlags
)
523 PRBool needUpdate
= (aFlags
!= mFlags
);
525 if (NS_LIKELY( needUpdate
&& mTree
)) {
527 nsCOMPtr
<nsIObserverService
> broadcaster
= do_GetService(
528 "@mozilla.org/observer-service;1");
529 NS_ENSURE_TRUE(broadcaster
, NS_OK
);
530 broadcaster
->NotifyObservers(reinterpret_cast<nsISupports
*>(this), "tree-flags-change", nsnull
);
535 /* Protected methods */
537 aaTreeView::postLoadHandler()
543 aaTreeView::getColumnIndex(nsITreeColumn
*col
, PRUint32 colPtrSz
)
546 NS_ENSURE_TRUE(col
, -1);
549 rv
= col
->GetIndex(&ci
);
550 NS_ENSURE_SUCCESS(rv
, -1);
552 NS_ENSURE_TRUE(ci
>= 0 && ci
< (PRInt32
) (colPtrSz
/ sizeof(int *)), -1);
558 aaTreeView::GetFilters(aaITreeViewFilters
**aFilters
)
560 NS_ENSURE_ARG_POINTER(aFilters
);
563 (new CTreeViewFilters
)->QueryInterface(NS_GET_IID(aaITreeViewFilters
), getter_AddRefs(mFilters
));
564 NS_ENSURE_TRUE(mFilters
, NS_ERROR_NULL_POINTER
);
566 if (NS_IF_ADDREF(mFilters
)) {
567 *aFilters
= mFilters
;
570 return NS_ERROR_FAILURE
;
576 aaTreeView::Next(PRInt16 type
, nsITreeColumn
*col
, const nsAString
& param
, PRBool
*_retval
)
579 NS_ENSURE_ARG_POINTER(col
);
580 NS_ENSURE_ARG_POINTER(_retval
);
581 NS_ENSURE_TRUE(mFilter
, NS_ERROR_NOT_INITIALIZED
);
583 if (PRInt16(aaITreeViewFilters::FILTER_SORT
) == type
) {
584 nsCOMPtr
<aaIOrderCondition
> order
;
586 //do create order condition
587 rc
= createOrderCondition(col
, param
, getter_AddRefs(order
));
588 NS_ENSURE_SUCCESS(rc
, rc
);
589 //do get condition name
590 rc
= order
->GetConditionName(name
);
591 NS_ENSURE_SUCCESS(rc
, rc
);
592 //do add order to filter
593 rc
= mFilter
->AddParam(name
, order
);
594 NS_ENSURE_SUCCESS(rc
, rc
);
595 } else if(PRInt16(aaITreeViewFilters::FILTER_FILTER
) == type
) {
596 nsCOMPtr
<aaIFilterCondition
> filter
;
598 //do create order condition
599 rc
= createFilterCondition(col
, param
, getter_AddRefs(filter
));
600 NS_ENSURE_SUCCESS(rc
, rc
);
601 //do get condition name
602 rc
= filter
->GetConditionName(name
);
603 NS_ENSURE_SUCCESS(rc
, rc
);
604 //do add order to filter
605 rc
= mFilter
->AddParam(name
, filter
);
606 NS_ENSURE_SUCCESS(rc
, rc
);
608 return NS_ERROR_INVALID_ARG
;
615 aaTreeView::buildFilter(nsISupports
* aParam
)
622 if (mFilters
|| aParam
) {
623 mFilter
= do_CreateInstance(AA_SQLFILTER_CONTRACT
, &rc
);
624 NS_ENSURE_SUCCESS(rc
, rc
);
628 nsCOMPtr
<aaITreeFilterObserver
> pObserver
;
629 this->QueryInterface(NS_GET_IID(aaITreeFilterObserver
), getter_AddRefs(pObserver
));
630 NS_ENSURE_SUCCESS(rc
, rc
);
632 rc
= mFilters
->Observe(pObserver
);
633 NS_ENSURE_SUCCESS(rc
, rc
);
637 //add param to filter
638 rc
= mFilter
->SetInterface(aParam
->GetIID(), aParam
);
639 NS_ENSURE_SUCCESS(rc
, rc
);
645 aaTreeView::createOrderCondition(nsITreeColumn
* col
, const nsAString
& param
, aaIOrderCondition
** _retval
)
648 nsCAutoString column
;
649 nsCOMPtr
<aaIOrderCondition
> order
;
651 NS_ENSURE_ARG_POINTER(col
);
652 NS_ENSURE_ARG_POINTER(_retval
);
653 NS_ENSURE_ARG_POINTER(!param
.IsEmpty());
655 order
= do_CreateInstance(AA_ORDER_CONDITION_CONTRACTID
, &rc
);
656 NS_ENSURE_SUCCESS(rc
, rc
);
658 rc
= convertSortColumnToString(col
, column
);
659 NS_ENSURE_SUCCESS(rc
, rc
);
661 rc
= order
->AddOrder(column
, (param
.Compare(NS_LITERAL_STRING("ascending")) == 0 ? PRInt16(aaIOrderCondition::SORT_ASC
) : PRInt16(aaIOrderCondition::SORT_DESC
)));
662 NS_ENSURE_SUCCESS(rc
, rc
);
664 if (NS_IF_ADDREF(order
)) {
668 return NS_ERROR_UNEXPECTED
;
674 aaTreeView::createFilterCondition(nsITreeColumn
* col
, const nsAString
& param
, aaIFilterCondition
** _retval
)
677 nsCAutoString column
;
678 nsCOMPtr
<aaIFilterCondition
> filter
;
680 NS_ENSURE_ARG_POINTER(col
);
681 NS_ENSURE_ARG_POINTER(_retval
);
682 NS_ENSURE_ARG_POINTER(!param
.IsEmpty());
684 filter
= do_CreateInstance(AA_FILTER_CONDITION_CONTRACTID
, &rc
);
685 NS_ENSURE_SUCCESS(rc
, rc
);
687 rc
= convertSortColumnToString(col
, column
);
688 NS_ENSURE_SUCCESS(rc
, rc
);
690 rc
= filter
->AddFilter(column
, NS_ConvertUTF16toUTF8(param
));
691 NS_ENSURE_SUCCESS(rc
, rc
);
693 if (NS_IF_ADDREF(filter
)) {
697 return NS_ERROR_UNEXPECTED
;
703 aaTreeView::dataLoadSuccess()