source: trunk/lib/html_utility.cc @ 284

Last change on this file since 284 was 284, checked in by Peter Johansson, 14 years ago

moved css generation to separate file

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.8 KB
Line 
1// $Id: html_utility.cc 284 2007-05-06 17:54:09Z peter $
2
3/*
4  Copyright (C) 2006, 2007 Peter Johansson
5
6  This file is part of svndigest, http://lev.thep.lu.se/trac/svndigest
7
8  svndigest is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  svndigest is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  02111-1307, USA.
22*/
23
24#include "html_utility.h"
25
26#include "Commitment.h"
27#include "Configuration.h"
28#include "Date.h"
29#include "HtmlStream.h"
30#include "Stats.h"
31#include "SVNlog.h"
32#include "utility.h"
33#include <config.h> // this header file is created by configure
34
35#include <algorithm>
36#include <cassert>
37#include <fstream>
38#include <iostream>
39#include <sstream>
40#include <stdexcept>
41#include <string>
42#include <sys/param.h>
43#include <unistd.h>
44#include <vector>
45
46namespace theplu{
47namespace svndigest{
48
49  std::string anchor(const std::string& href, 
50                     const std::string& name, u_int level, 
51                     const std::string& title)
52  {
53    std::stringstream ss;
54    HtmlStream hs(ss);
55    ss << "<a title=\"";
56    hs << title; 
57    ss << "\" href=\"";
58    for (size_t i=0; i<level; ++i)
59      ss << "../";
60    hs << href; 
61    ss << "\">"; 
62    hs << name; 
63    ss << "</a>";
64    return ss.str();
65  }
66
67 
68  void print_main_page(const std::string& dir, const SVNlog& log,
69                       const Stats& stats)
70  {
71    std::string filename="index.html";
72    std::ofstream os(filename.c_str());
73    print_header(os, dir, 0, "all", "main", "index.html");
74
75    using namespace std;
76    set<string> authors;
77    authors.insert(log.author().begin(), log.author().end());
78    // erase invalid authors
79    authors.erase("");
80    authors.erase("no author");
81
82    vector<Commitment> latest_commit;
83    latest_commit.reserve(authors.size());
84    for (set<string>::const_iterator i(authors.begin()); i!=authors.end(); ++i)
85      latest_commit.push_back(log.latest_commit(*i));
86
87    print_general_information(os, log, authors.size());
88    sort(latest_commit.begin(), latest_commit.end(), GreaterRevision());
89    print_authors(os, latest_commit, stats);
90    print_recent_logs(os, log);
91    os << "<hr width=100% />";
92    print_footer(os);
93    os.close();
94
95  }
96
97  void print_general_information(std::ostream& os, const SVNlog& log, 
98                                 size_t nof_authors)
99  { 
100    Date begin(log.date()[0]);
101    if (log.date().size()>1)
102      begin = std::min(begin, Date(log.date()[1]));
103    Date end(log.date().back());
104    Date now;
105    std::string timefmt("%a, %e %b %Y");
106
107    os << "<div class=\"main\">" 
108       << "<table class=\"main\"><thead><tr><th colspan=\"2\">" 
109       << "General Information"
110       << "</th></tr></thead>\n"
111       << "<tr><td>First Revision:</td><td>" 
112       << begin(timefmt) << "</td></tr>\n"
113       << "<tr><td>Latest Revision:</td><td>" 
114       << end(timefmt) << "</td></tr>\n"
115       << "<tr><td>Report Generated:</td><td>" 
116       << now(timefmt) << "</td></tr>\n"
117       << "<tr><td>Repository Age:</td><td>"; 
118    os << now.difftime(begin);
119    os << "</td></tr>\n"
120       << "<tr><td>Number of Authors:</td><td>" << nof_authors
121       << "</td></tr>\n"
122       << "<tr><td>Revisions:</td><td>" << log.revision().size() 
123       << "</td></tr>\n"
124       << "</table></div>\n";
125  }
126
127
128  void print_footer(std::ostream& os)
129  {
130    Date date;
131    os << "<p align=center><font size=-2>\nGenerated on "
132       << date("%a %b %d %H:%M:%S %Y") << " (UTC) by "
133       << anchor("http://lev.thep.lu.se/trac/svndigest/", 
134                 PACKAGE_STRING, 0, "")
135       << "</font>\n</p>\n</div>\n</body>\n</html>\n";
136  }
137
138
139  void print_header(std::ostream& os, std::string title, u_int level,
140                    std::string user, std::string item, std::string path)
141  {
142    os << "<!DOCTYPE html\n"
143       << "PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
144       << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
145       << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
146       << " xml:lang=\"en\" lang=\"en\"><head>\n"
147       << "<head>\n"
148       << "<title> " << title << " - svndigest</title>\n"
149       << "</head>\n"
150       << "<link rel=\"stylesheet\" "
151       << "href=\"";
152    for (u_int i=0; i<level; ++i)
153      os << "../";
154    os << "svndigest.css\" type=\"text/css\" />\n"
155       << "<body>\n"
156       << "<div id=\"menu\">"
157       << "<ul><li></li>";
158    if (item=="main")
159      os << "<li class=\"highlight\">";
160    else
161      os << "<li>";
162    os << anchor("index.html", "Main", level, "Main page");
163    os << "</li>";
164
165    if (item=="total")
166      os << "<li class=\"highlight\">";
167    else
168      os << "<li>";
169    os << anchor(user+"/total/"+path, "Total", level, 
170           "View statistics of all lines");
171    os << "</li>";
172
173    if (item=="code")
174      os << "<li class=\"highlight\">";
175    else
176      os << "<li>";
177    os << anchor(user+"/code/"+path, "Code", level, 
178                 "View statistics of code lines");
179    os << "</li>";
180
181    if (item=="comments")
182      os << "<li class=\"highlight\">";
183    else
184      os << "<li>";
185    os << anchor(user+"/comments/"+path, "Comment", level, 
186                 "View statistics of comment lines");
187    os << "</li>";
188
189
190    if (item=="empty")
191      os << "<li class=\"highlight\">";
192    else
193      os << "<li>";
194    os << anchor(user+"/empty/"+path, "Other", level, 
195                 "View statistics of empty lines");
196    os << "</li>"
197       << "</ul></div>"
198       << "<div id=\"main\">\n";
199  }
200
201
202  void print_authors(std::ostream& os, 
203                     const std::vector<Commitment>& lc,
204                     const Stats& stats)
205  {
206    os << "<div class=\"main\">"
207       << "<table class=\"main\"><thead><tr><th colspan=\"2\">" 
208       << "Authors"
209       << "</th></tr></thead>\n";
210
211    os << "<tr><td>Author</td>" 
212       << "<td>Number of Lines</td>"
213       << "<td>Code Lines</td>"
214       << "<td>Comment Lines</td>"
215       << "<td>Latest Commitment</td>"
216       <<"</tr>";
217
218    std::string timefmt("%b %d %H:%M:%S %Y");
219    using namespace std;
220    for (vector<Commitment>::const_iterator i=lc.begin(); i!=lc.end(); ++i) {
221      os << "<tr><td>" 
222         << anchor(string(i->author()+"/total/index.html"),i->author())
223         << "</td><td>" << stats.lines(i->author()) << " (" 
224         << 100*stats.lines(i->author())/stats.lines() << "%)</td>"
225         << "<td>" << stats.code(i->author()) << " (" 
226         << 100*stats.code(i->author())/stats.code() << "%)</td>"
227         << "<td>" << stats.comments(i->author()) << " (" 
228         << 100*stats.comments(i->author())/stats.comments() << "%)</td>"
229         << "<td>" << i->date()(timefmt) << "</td>"
230         <<"</tr>";
231    }
232
233    os << "</table></div>\n";
234   
235  }
236
237
238  void print_recent_logs(std::ostream& os, const SVNlog& log)
239  {
240    os << "<div class=\"main\">\n"
241       << "<table class=\"main\"><thead><tr><th colspan=\"2\">" 
242       << "Recent Log"
243       << "</th></tr></thead>\n";
244
245    std::vector<std::string>::const_reverse_iterator a=log.author().rbegin();
246    std::vector<std::string>::const_reverse_iterator d=log.date().rbegin();
247    std::vector<std::string>::const_reverse_iterator m=log.message().rbegin();
248    std::vector<size_t>::const_reverse_iterator r=log.revision().rbegin();
249    assert(log.author().size()==log.date().size());
250    assert(log.author().size()==log.message().size());
251    assert(log.author().size()==log.revision().size());
252    os << "<tr><td>Author</td><td>Date</td><td>Rev</td><td>Message</td></tr>\n";
253    HtmlStream hs(os);
254    std::string timefmt("%b %d %H:%M:%S %Y");
255    const size_t maxlength = 80;
256    const Configuration* conf = Configuration::instance();
257    for (size_t i=0; i<10 && a!=log.author().rend(); ++i) {
258      os << "<tr><td>" << anchor(*a+"/total/index.html",*a) << "</td>";
259      Date date(*d);
260      os << "<td>" << date(timefmt) << "</td>";
261      os << "<td>"; 
262      os << trac_revision(*r);
263      os << "</td>";
264      os << "<td>";
265      std::string mess = *m;
266      // replace newlines with space
267      std::replace(mess.begin(), mess.end(), '\n', ' ');
268      mess = htrim(mess);
269      // truncate message if too long
270      if (mess.size()>maxlength)
271        mess = mess.substr(0,maxlength-3) + "...";
272
273      if (conf->trac_ticket().empty())
274        hs << mess;
275      else { // make anchors to trac
276        char c;
277        std::stringstream ss(mess);
278        for (ss.get(c); ss.good(); ss.get(c)) {
279          if (c=='#') {
280            int ticket=0;
281            ss >> ticket;
282            if (!ss.fail()){
283              std::stringstream s;
284              s << ticket;
285              os << anchor(conf->trac_ticket()+s.str(),"#"+s.str()); 
286            }
287            else {
288              ss.clear(std::ios::goodbit);
289              hs << c;
290            }
291          }
292          else
293            hs << c;
294        }
295      }
296
297      os << "</td></tr>";
298      ++a;
299      ++d;
300      ++m;
301      ++r;
302    }
303    os << "</table></div>\n";
304  }
305
306
307  std::string trac_revision(size_t r)
308  {
309    Configuration* conf = Configuration::instance();
310    std::stringstream ss;
311    if (conf->trac_revision().empty())
312      ss << r; 
313    else {
314      std::stringstream rev;
315      rev << r;
316      ss << anchor(conf->trac_revision()+rev.str(), rev.str());
317    }
318    return ss.str();
319  }
320
321}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.