Move HtmlEscape (escape for qt rich text controls) to qt gui utilities
[novacoin.git] / src / qt / transactiondesc.cpp
1 #include <transactiondesc.h>
2
3 #include "guiutil.h"
4 #include "bitcoinunits.h"
5
6 #include "headers.h"
7 #include "qtui.h"
8
9 #include <QString>
10
11 using namespace std;
12
13 QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
14 {
15     if (!wtx.IsFinal())
16     {
17         if (wtx.nLockTime < LOCKTIME_THRESHOLD)
18             return tr("Open for %1 blocks").arg(nBestHeight - wtx.nLockTime);
19         else
20             return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
21     }
22     else
23     {
24         int nDepth = wtx.GetDepthInMainChain();
25         if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
26             return tr("%1/offline?").arg(nDepth);
27         else if (nDepth < 6)
28             return tr("%1/unconfirmed").arg(nDepth);
29         else
30             return tr("%1 confirmations").arg(nDepth);
31     }
32 }
33
34 QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
35 {
36     QString strHTML;
37     CRITICAL_BLOCK(wallet->cs_wallet)
38     {
39         strHTML.reserve(4000);
40         strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
41
42         int64 nTime = wtx.GetTxTime();
43         int64 nCredit = wtx.GetCredit();
44         int64 nDebit = wtx.GetDebit();
45         int64 nNet = nCredit - nDebit;
46
47         strHTML += tr("<b>Status:</b> ") + FormatTxStatus(wtx);
48         int nRequests = wtx.GetRequestCount();
49         if (nRequests != -1)
50         {
51             if (nRequests == 0)
52                 strHTML += tr(", has not been successfully broadcast yet");
53             else if (nRequests == 1)
54                 strHTML += tr(", broadcast through %1 node").arg(nRequests);
55             else
56                 strHTML += tr(", broadcast through %1 nodes").arg(nRequests);
57         }
58         strHTML += "<br>";
59
60         strHTML += tr("<b>Date:</b> ") + (nTime ? GUIUtil::dateTimeStr(nTime) : QString("")) + "<br>";
61
62         //
63         // From
64         //
65         if (wtx.IsCoinBase())
66         {
67             strHTML += tr("<b>Source:</b> Generated<br>");
68         }
69         else if (!wtx.mapValue["from"].empty())
70         {
71             // Online transaction
72             if (!wtx.mapValue["from"].empty())
73                 strHTML += tr("<b>From:</b> ") + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
74         }
75         else
76         {
77             // Offline transaction
78             if (nNet > 0)
79             {
80                 // Credit
81                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
82                 {
83                     if (wallet->IsMine(txout))
84                     {
85                         CBitcoinAddress address;
86                         if (ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address))
87                         {
88                             if (wallet->mapAddressBook.count(address))
89                             {
90                                 strHTML += tr("<b>From:</b> ") + tr("unknown") + "<br>";
91                                 strHTML += tr("<b>To:</b> ");
92                                 strHTML += GUIUtil::HtmlEscape(address.ToString());
93                                 if (!wallet->mapAddressBook[address].empty())
94                                     strHTML += tr(" (yours, label: ") + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
95                                 else
96                                     strHTML += tr(" (yours)");
97                                 strHTML += "<br>";
98                             }
99                         }
100                         break;
101                     }
102                 }
103             }
104         }
105
106         //
107         // To
108         //
109         string strAddress;
110         if (!wtx.mapValue["to"].empty())
111         {
112             // Online transaction
113             strAddress = wtx.mapValue["to"];
114             strHTML += tr("<b>To:</b> ");
115             if (wallet->mapAddressBook.count(strAddress) && !wallet->mapAddressBook[strAddress].empty())
116                 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[strAddress]) + " ";
117             strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
118         }
119
120         //
121         // Amount
122         //
123         if (wtx.IsCoinBase() && nCredit == 0)
124         {
125             //
126             // Coinbase
127             //
128             int64 nUnmatured = 0;
129             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
130                 nUnmatured += wallet->GetCredit(txout);
131             strHTML += tr("<b>Credit:</b> ");
132             if (wtx.IsInMainChain())
133                 strHTML += tr("(%1 matures in %2 more blocks)")
134                         .arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured))
135                         .arg(wtx.GetBlocksToMaturity());
136             else
137                 strHTML += tr("(not accepted)");
138             strHTML += "<br>";
139         }
140         else if (nNet > 0)
141         {
142             //
143             // Credit
144             //
145             strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>";
146         }
147         else
148         {
149             bool fAllFromMe = true;
150             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
151                 fAllFromMe = fAllFromMe && wallet->IsMine(txin);
152
153             bool fAllToMe = true;
154             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
155                 fAllToMe = fAllToMe && wallet->IsMine(txout);
156
157             if (fAllFromMe)
158             {
159                 //
160                 // Debit
161                 //
162                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
163                 {
164                     if (wallet->IsMine(txout))
165                         continue;
166
167                     if (wtx.mapValue["to"].empty())
168                     {
169                         // Offline transaction
170                         CBitcoinAddress address;
171                         if (ExtractAddress(txout.scriptPubKey, address))
172                         {
173                             strHTML += tr("<b>To:</b> ");
174                             if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
175                                 strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
176                             strHTML += GUIUtil::HtmlEscape(address.ToString());
177                             strHTML += "<br>";
178                         }
179                     }
180
181                     strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>";
182                 }
183
184                 if (fAllToMe)
185                 {
186                     // Payment to self
187                     int64 nChange = wtx.GetChange();
188                     int64 nValue = nCredit - nChange;
189                     strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>";
190                     strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
191                 }
192
193                 int64 nTxFee = nDebit - wtx.GetValueOut();
194                 if (nTxFee > 0)
195                     strHTML += tr("<b>Transaction fee:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-nTxFee) + "<br>";
196             }
197             else
198             {
199                 //
200                 // Mixed debit transaction
201                 //
202                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
203                     if (wallet->IsMine(txin))
204                         strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-wallet->GetDebit(txin)) + "<br>";
205                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
206                     if (wallet->IsMine(txout))
207                         strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,wallet->GetCredit(txout)) + "<br>";
208             }
209         }
210
211         strHTML += tr("<b>Net amount:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,nNet, true) + "<br>";
212
213         //
214         // Message
215         //
216         if (!wtx.mapValue["message"].empty())
217             strHTML += QString("<br><b>") + tr("Message:") + "</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
218         if (!wtx.mapValue["comment"].empty())
219             strHTML += QString("<br><b>") + tr("Comment:") + "</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
220
221         if (wtx.IsCoinBase())
222             strHTML += QString("<br>") + tr("Generated coins must wait 120 blocks before they can be spent.  When you generated this block, it was broadcast to the network to be added to the block chain.  If it fails to get into the chain, it will change to \"not accepted\" and not be spendable.  This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>";
223
224         //
225         // Debug view
226         //
227         if (fDebug)
228         {
229             strHTML += "<hr><br>Debug information<br><br>";
230             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
231                 if(wallet->IsMine(txin))
232                     strHTML += "<b>Debit:</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-wallet->GetDebit(txin)) + "<br>";
233             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
234                 if(wallet->IsMine(txout))
235                     strHTML += "<b>Credit:</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,wallet->GetCredit(txout)) + "<br>";
236
237             strHTML += "<br><b>Transaction:</b><br>";
238             strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
239
240             CTxDB txdb("r"); // To fetch source txouts
241
242             strHTML += "<br><b>Inputs:</b>";
243             strHTML += "<ul>";
244             CRITICAL_BLOCK(wallet->cs_wallet)
245             {
246                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
247                 {
248                     COutPoint prevout = txin.prevout;
249
250                     CTransaction prev;
251                     if(txdb.ReadDiskTx(prevout.hash, prev))
252                     {
253                         if (prevout.n < prev.vout.size())
254                         {
255                             strHTML += "<li>";
256                             const CTxOut &vout = prev.vout[prevout.n];
257                             CBitcoinAddress address;
258                             if (ExtractAddress(vout.scriptPubKey, address))
259                             {
260                                 if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
261                                     strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
262                                 strHTML += QString::fromStdString(address.ToString());
263                             }
264                             strHTML = strHTML + " Amount=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,vout.nValue);
265                             strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? "true" : "false") + "</li>";
266                         }
267                     }
268                 }
269             }
270             strHTML += "</ul>";
271         }
272
273         strHTML += "</font></html>";
274     }
275     return strHTML;
276 }