KReport

KReportSectionEditor.cpp
1 /* This file is part of the KDE project
2  * Copyright (C) 2001-2007 by OpenMFG, LLC ([email protected])
3  * Copyright (C) 2007-2008 by Adam Pigg ([email protected])
4  * Copyright (C) 2012 by Friedrich W. H. Kossebau ([email protected])
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "KReportSectionEditor.h"
21 
22 #include "KReportDesigner.h"
23 #include "KReportSection.h"
24 #include "KReportDesignerSectionDetail.h"
25 #include "KReportDetailGroupSectionDialog.h"
26 #include "KReportDesignerSectionDetailGroup.h"
27 
28 #include <QIcon>
29 #include <QDialogButtonBox>
30 #include <QVBoxLayout>
31 #include <QPushButton>
32 
33 enum {
34  KeyRole = Qt::UserRole
35 };
36 
37 // KReportDesigner currently prepends an empty key/fieldname pair to the list
38 // of fields, possibly to offer the option to have report elements not yet
39 // bound to fields
40 static inline bool isEditorHelperField(const QString &key)
41 {
42  return key.isEmpty();
43 }
44 
45 /*
46  * Constructs a SectionEditor as a child of 'parent'.
47  *
48  * The dialog will by default be modeless, unless you set 'modal' to
49  * true to construct a modal dialog.
50  */
51 KReportSectionEditor::KReportSectionEditor(KReportDesigner* designer)
52  : QDialog(designer)
53 {
54  Q_ASSERT(designer);
55  m_reportDesigner = designer;
56  m_reportSectionDetail = m_reportDesigner->detailSection();
57 
58  //! @todo check section editor
59  //setButtons(Close);
60  //setCaption(tr("Section Editor"));
61 
63  QVBoxLayout* mainLayout = new QVBoxLayout(this);
64  QPushButton* closeButton = buttonBox->button(QDialogButtonBox::Close);
65 
66  closeButton->setDefault(true);
67  closeButton->setShortcut(Qt::CTRL | Qt::Key_Return);
68  connect(buttonBox, SIGNAL(rejected()), this, SLOT(accept()));
69 
70  QWidget *widget = new QWidget(this);
71  m_ui.setupUi(widget);
72  m_btnAdd = new QPushButton(QIcon::fromTheme(QLatin1String("list-add")), tr("Add..."), this);
73  m_ui.lGroupSectionsButtons->addWidget(m_btnAdd);
74  m_btnEdit = new QPushButton(QIcon::fromTheme(QLatin1String("document-edit")), tr("Edit..."), this);
75  m_ui.lGroupSectionsButtons->addWidget(m_btnEdit);
76  m_btnRemove = new QPushButton(QIcon::fromTheme(QLatin1String("list-remove")), tr("Delete"), this);
77  m_ui.lGroupSectionsButtons->addWidget(m_btnRemove);
78  m_btnMoveUp = new QPushButton(QIcon::fromTheme(QLatin1String("arrow-up")), tr("Move Up"), this);
79  m_ui.lGroupSectionsButtons->addWidget(m_btnMoveUp);
80  m_btnMoveDown = new QPushButton(QIcon::fromTheme(QLatin1String("arrow-down")), tr("Move Down"), this);
81  m_ui.lGroupSectionsButtons->addWidget(m_btnMoveDown);
82  m_ui.lGroupSectionsButtons->addStretch();
83 
84  mainLayout->addWidget(widget);
85  mainLayout->addWidget(buttonBox);
86 
87  //setMainWidget(widget);
88 
89  // signals and slots connections
90  connect(m_ui.cbReportHeader, SIGNAL(toggled(bool)), this, SLOT(cbReportHeader_toggled(bool)));
91  connect(m_ui.cbReportFooter, SIGNAL(toggled(bool)), this, SLOT(cbReportFooter_toggled(bool)));
92  connect(m_ui.cbHeadFirst, SIGNAL(toggled(bool)), this, SLOT(cbHeadFirst_toggled(bool)));
93  connect(m_ui.cbHeadLast, SIGNAL(toggled(bool)), this, SLOT(cbHeadLast_toggled(bool)));
94  connect(m_ui.cbHeadEven, SIGNAL(toggled(bool)), this, SLOT(cbHeadEven_toggled(bool)));
95  connect(m_ui.cbHeadOdd, SIGNAL(toggled(bool)), this, SLOT(cbHeadOdd_toggled(bool)));
96  connect(m_ui.cbFootFirst, SIGNAL(toggled(bool)), this, SLOT(cbFootFirst_toggled(bool)));
97  connect(m_ui.cbFootLast, SIGNAL(toggled(bool)), this, SLOT(cbFootLast_toggled(bool)));
98  connect(m_ui.cbFootEven, SIGNAL(toggled(bool)), this, SLOT(cbFootEven_toggled(bool)));
99  connect(m_ui.cbFootOdd, SIGNAL(toggled(bool)), this, SLOT(cbFootOdd_toggled(bool)));
100  connect(m_ui.cbHeadAny, SIGNAL(toggled(bool)), this, SLOT(cbHeadAny_toggled(bool)));
101  connect(m_ui.cbFootAny, SIGNAL(toggled(bool)), this, SLOT(cbFootAny_toggled(bool)));
102  connect(m_ui.lbGroups, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
103  this, SLOT(updateButtonsForItem(QListWidgetItem*)));
104  connect(m_ui.lbGroups, SIGNAL(currentRowChanged(int)),
105  this, SLOT(updateButtonsForRow(int)));
106 
107  connect(m_btnAdd, SIGNAL(clicked(bool)), this, SLOT(btnAdd_clicked()));
108  connect(m_btnEdit, SIGNAL(clicked(bool)), this, SLOT(btnEdit_clicked()));
109  connect(m_btnRemove, SIGNAL(clicked(bool)), this, SLOT(btnRemove_clicked()));
110  connect(m_btnMoveUp, SIGNAL(clicked(bool)), this, SLOT(btnMoveUp_clicked()));
111  connect(m_btnMoveDown, SIGNAL(clicked(bool)), this, SLOT(brnMoveDown_clicked()));
112 
113  // set all the properties
114 
115  m_ui.cbReportHeader->setChecked(m_reportDesigner->section(KReportSectionData::Type::ReportHeader));
116  m_ui.cbReportFooter->setChecked(m_reportDesigner->section(KReportSectionData::Type::ReportFooter));
117 
118  m_ui.cbHeadFirst->setChecked(m_reportDesigner->section(KReportSectionData::Type::PageHeaderFirst));
119  m_ui.cbHeadOdd->setChecked(m_reportDesigner->section(KReportSectionData::Type::PageHeaderOdd));
120  m_ui.cbHeadEven->setChecked(m_reportDesigner->section(KReportSectionData::Type::PageHeaderEven));
121  m_ui.cbHeadLast->setChecked(m_reportDesigner->section(KReportSectionData::Type::PageHeaderLast));
122  m_ui.cbHeadAny->setChecked(m_reportDesigner->section(KReportSectionData::Type::PageHeaderAny));
123 
124  m_ui.cbFootFirst->setChecked(m_reportDesigner->section(KReportSectionData::Type::PageFooterFirst));
125  m_ui.cbFootOdd->setChecked(m_reportDesigner->section(KReportSectionData::Type::PageFooterOdd));
126  m_ui.cbFootEven->setChecked(m_reportDesigner->section(KReportSectionData::Type::PageFooterEven));
127  m_ui.cbFootLast->setChecked(m_reportDesigner->section(KReportSectionData::Type::PageFooterLast));
128  m_ui.cbFootAny->setChecked(m_reportDesigner->section(KReportSectionData::Type::PageFooterAny));
129 
130  // now set the rw value
131  if (m_reportSectionDetail) {
132  const QStringList columnNames = m_reportDesigner->fieldNames();
133  const QStringList keys = m_reportDesigner->fieldKeys();
134  for (int i = 0; i < m_reportSectionDetail->groupSectionCount(); ++i) {
135  const QString key = m_reportSectionDetail->groupSection(i)->column();
136  const int idx = keys.indexOf(key);
137  const QString columnName = columnNames.value(idx);
138  QListWidgetItem *item = new QListWidgetItem(columnName);
139  item->setData(KeyRole, key);
140  m_ui.lbGroups->addItem(item);
141  }
142  }
143  if (m_ui.lbGroups->count() == 0) {
144  } else {
145  m_ui.lbGroups->setCurrentItem(m_ui.lbGroups->item(0));
146  }
147  updateButtonsForItem(m_ui.lbGroups->currentItem());
148  updateAddButton();
149  updateButtonsForRow(m_ui.lbGroups->currentRow());
150 }
151 
152 /*
153  * Destroys the object and frees any allocated resources
154  */
155 KReportSectionEditor::~KReportSectionEditor()
156 {
157  // no need to delete child widgets, Qt does it all for us
158 }
159 
160 void KReportSectionEditor::cbReportHeader_toggled(bool yes)
161 {
162  if (m_reportDesigner) {
163  if (yes) {
164  m_reportDesigner->insertSection(KReportSectionData::Type::ReportHeader);
165  } else {
166  m_reportDesigner->removeSection(KReportSectionData::Type::ReportHeader);
167  }
168  }
169 
170 }
171 
172 void KReportSectionEditor::cbReportFooter_toggled(bool yes)
173 {
174  if (m_reportDesigner) {
175  if (yes) {
176  m_reportDesigner->insertSection(KReportSectionData::Type::ReportFooter);
177  } else {
178  m_reportDesigner->removeSection(KReportSectionData::Type::ReportFooter);
179  }
180  }
181 
182 }
183 
184 void KReportSectionEditor::cbHeadFirst_toggled(bool yes)
185 {
186  if (m_reportDesigner) {
187  if (yes) {
188  m_reportDesigner->insertSection(KReportSectionData::Type::PageHeaderFirst);
189  } else {
190  m_reportDesigner->removeSection(KReportSectionData::Type::PageHeaderFirst);
191  }
192  }
193 
194 }
195 
196 void KReportSectionEditor::cbHeadLast_toggled(bool yes)
197 {
198  if (m_reportDesigner) {
199  if (yes) {
200  m_reportDesigner->insertSection(KReportSectionData::Type::PageHeaderLast);
201  } else {
202  m_reportDesigner->removeSection(KReportSectionData::Type::PageHeaderLast);
203  }
204  }
205 
206 }
207 
208 void KReportSectionEditor::cbHeadEven_toggled(bool yes)
209 {
210  if (m_reportDesigner) {
211  if (yes) {
212  m_reportDesigner->insertSection(KReportSectionData::Type::PageHeaderEven);
213  } else {
214  m_reportDesigner->removeSection(KReportSectionData::Type::PageHeaderEven);
215  }
216  }
217 
218 }
219 
220 void KReportSectionEditor::cbHeadOdd_toggled(bool yes)
221 {
222  if (m_reportDesigner) {
223  if (yes) {
224  m_reportDesigner->insertSection(KReportSectionData::Type::PageHeaderOdd);
225  } else {
226  m_reportDesigner->removeSection(KReportSectionData::Type::PageHeaderOdd);
227  }
228  }
229 
230 }
231 
232 void KReportSectionEditor::cbFootFirst_toggled(bool yes)
233 {
234  if (m_reportDesigner) {
235  if (yes) {
236  m_reportDesigner->insertSection(KReportSectionData::Type::PageFooterFirst);
237  } else {
238  m_reportDesigner->removeSection(KReportSectionData::Type::PageFooterFirst);
239  }
240  }
241 
242 }
243 
244 void KReportSectionEditor::cbFootLast_toggled(bool yes)
245 {
246  if (m_reportDesigner) {
247  if (yes) {
248  m_reportDesigner->insertSection(KReportSectionData::Type::PageFooterLast);
249  } else {
250  m_reportDesigner->removeSection(KReportSectionData::Type::PageFooterLast);
251  }
252  }
253 
254 }
255 
256 void KReportSectionEditor::cbFootEven_toggled(bool yes)
257 {
258  if (m_reportDesigner) {
259  if (yes) {
260  m_reportDesigner->insertSection(KReportSectionData::Type::PageFooterEven);
261  } else {
262  m_reportDesigner->removeSection(KReportSectionData::Type::PageFooterEven);
263  }
264  }
265 
266 }
267 
268 void KReportSectionEditor::cbFootOdd_toggled(bool yes)
269 {
270  if (m_reportDesigner) {
271  if (yes) {
272  m_reportDesigner->insertSection(KReportSectionData::Type::PageFooterOdd);
273  } else {
274  m_reportDesigner->removeSection(KReportSectionData::Type::PageFooterOdd);
275  }
276  }
277 
278 }
279 
280 bool KReportSectionEditor::editDetailGroup(KReportDesignerSectionDetailGroup * rsdg)
281 {
282  KReportDetailGroupSectionDialog * dgsd = new KReportDetailGroupSectionDialog(this);
283 
284  // add the current column and all columns not yet used for groups
285  const QStringList keys = m_reportDesigner->fieldKeys();
286  const QStringList columnNames = m_reportDesigner->fieldNames();
287  // in case of to-be-added group that column needs to be added to the used
288  const QSet<QString> usedColumns = groupingColumns() << rsdg->column();
289  // if the current column is not among the keys, something is broken.
290  // for now just simply select no column in the combobox, achieved by -1
291  int indexOfCurrentColumn = -1;
292  for (int i = 0; i < keys.count(); ++i) {
293  const QString &key = keys.at(i);
294  // skip any editor helper fields
295  if (isEditorHelperField(key)) {
296  continue;
297  }
298  // already used?
299  if (usedColumns.contains(key)) {
300  // and not the one of the group?
301  if (key != rsdg->column()) {
302  continue;
303  }
304  // remember index
305  indexOfCurrentColumn = dgsd->cbColumn->count();
306  }
307  dgsd->cbColumn->insertItem( i, columnNames.value(i), key);
308  }
309  dgsd->cbColumn->setCurrentIndex(indexOfCurrentColumn);
310 
311  dgsd->cbSort->addItem(tr("Ascending"), Qt::AscendingOrder);
312  dgsd->cbSort->addItem(tr("Descending"), Qt::DescendingOrder);
313  dgsd->cbSort->setCurrentIndex(dgsd->cbSort->findData(rsdg->sort()));
314 
315  dgsd->breakAfterFooter->setChecked(rsdg->pageBreak() == KReportDesignerSectionDetailGroup::PageBreak::AfterGroupFooter);
316  dgsd->cbHead->setChecked(rsdg->groupHeaderVisible());
317  dgsd->cbFoot->setChecked(rsdg->groupFooterVisible());
318 
319  const bool isOkayed = (dgsd->exec() == QDialog::Accepted);
320 
321  if (isOkayed) {
322  const QString newColumn =
323  dgsd->cbColumn->itemData(dgsd->cbColumn->currentIndex()).toString();
324  const QString oldColumn = rsdg->column();
325  if (newColumn != oldColumn) {
326  rsdg->setColumn(newColumn);
327  }
328 
329  rsdg->setGroupHeaderVisible(dgsd->cbHead->isChecked());
330  rsdg->setGroupFooterVisible(dgsd->cbFoot->isChecked());
331 
332  const KReportDesignerSectionDetailGroup::PageBreak pageBreak
333  = dgsd->breakAfterFooter->isChecked()
334  ? KReportDesignerSectionDetailGroup::PageBreak::AfterGroupFooter
335  : KReportDesignerSectionDetailGroup::PageBreak::None;
336  rsdg->setPageBreak(pageBreak);
337 
338  const Qt::SortOrder sortOrder =
339  static_cast<Qt::SortOrder>(dgsd->cbSort->itemData(dgsd->cbSort->currentIndex()).toInt());
340  rsdg->setSort(sortOrder);
341  }
342 
343  delete dgsd;
344 
345  return isOkayed;
346 }
347 
348 QString KReportSectionEditor::columnName(const QString &column) const
349 {
350  const QStringList keys = m_reportDesigner->fieldKeys();
351  const QStringList columnNames = m_reportDesigner->fieldNames();
352  return columnNames.at(keys.indexOf(column));
353 }
354 
355 QSet<QString> KReportSectionEditor::groupingColumns() const
356 {
357  QSet<QString> result;
358  for (int i = 0; i < m_ui.lbGroups->count(); ++i) {
359  result.insert(m_ui.lbGroups->item(i)->data(KeyRole).toString());
360  }
361  return result;
362 }
363 
364 void KReportSectionEditor::cbHeadAny_toggled(bool yes)
365 {
366  if (m_reportDesigner) {
367  if (yes) {
368  m_reportDesigner->insertSection(KReportSectionData::Type::PageHeaderAny);
369  } else {
370  m_reportDesigner->removeSection(KReportSectionData::Type::PageHeaderAny);
371  }
372  }
373 }
374 
375 void KReportSectionEditor::cbFootAny_toggled(bool yes)
376 {
377  if (m_reportDesigner) {
378  if (yes) {
379  m_reportDesigner->insertSection(KReportSectionData::Type::PageFooterAny);
380  } else {
381  m_reportDesigner->removeSection(KReportSectionData::Type::PageFooterAny);
382  }
383  }
384 }
385 
386 void KReportSectionEditor::btnEdit_clicked()
387 {
388  if (m_reportSectionDetail) {
389  const int idx = m_ui.lbGroups->currentRow();
390  if (idx < 0) {
391  return;
392  }
393  KReportDesignerSectionDetailGroup * rsdg = m_reportSectionDetail->groupSection(idx);
394  if (editDetailGroup(rsdg)) {
395  // update name in list
396  m_ui.lbGroups->item(idx)->setText(columnName(rsdg->column()));
397  }
398  }
399 }
400 
401 void KReportSectionEditor::btnAdd_clicked()
402 {
403  if (m_reportSectionDetail) {
404  // lets add a new section
405  // search for unused column
406  QString column;
407  const QStringList keys = m_reportDesigner->fieldKeys();
408  const QSet<QString> columns = groupingColumns();
409  foreach(const QString &key, keys) {
410  // skip any editor helper fields
411  if (isEditorHelperField(key)) {
412  continue;
413  }
414  if (! columns.contains(key)) {
415  column = key;
416  break;
417  }
418  }
419  // should not happen, but we do not really know if m_reportDesigner is in sync
420  if (column.isEmpty()) {
421  return;
422  }
423 
424  // create new group, have it edited and add it, if not cancelled
426  new KReportDesignerSectionDetailGroup(column, m_reportSectionDetail, m_reportSectionDetail);
427  if (editDetailGroup(rsdg)) {
428  // append to group sections
429  m_reportSectionDetail->insertGroupSection(m_reportSectionDetail->groupSectionCount(), rsdg);
430  // add to combobox
431  const QString column = rsdg->column();
432  QListWidgetItem *item = new QListWidgetItem(columnName(column));
433  item->setData(KeyRole, column);
434  m_ui.lbGroups->addItem(item);
435  m_ui.lbGroups->setCurrentRow(m_ui.lbGroups->count() - 1);
436  updateAddButton();
437  } else {
438  delete rsdg;
439  }
440  }
441 }
442 
443 
444 void KReportSectionEditor::btnRemove_clicked()
445 {
446  if (m_reportSectionDetail) {
447  const int index = m_ui.lbGroups->currentRow();
448  if (index != -1) {
449  QListWidgetItem *item = m_ui.lbGroups->takeItem(index);
450  delete item;
451  m_reportSectionDetail->removeGroupSection(index, true);
452  // a field got usable, so make sure add button is available again
453  m_btnAdd->setEnabled(true);
454  // workaround for at least Qt 4.8.1, which does not emit the proper
455  // currentRowChanged signal on deletion of the first element
456  updateButtonsForRow(m_ui.lbGroups->currentRow());
457  }
458  }
459 }
460 
461 
462 void KReportSectionEditor::btnMoveUp_clicked()
463 {
464  if (m_reportSectionDetail) {
465  int idx = m_ui.lbGroups->currentRow();
466  if (idx <= 0) return;
467  QString s = m_ui.lbGroups->currentItem()->text();
468  m_ui.lbGroups->takeItem(idx);
469  m_ui.lbGroups->insertItem(idx - 1, s);
470  m_ui.lbGroups->setCurrentRow(idx - 1, QItemSelectionModel::ClearAndSelect);
471  KReportDesignerSectionDetailGroup * rsdg = m_reportSectionDetail->groupSection(idx);
472  bool showgh = rsdg->groupHeaderVisible();
473  bool showgf = rsdg->groupFooterVisible();
474  m_reportSectionDetail->removeGroupSection(idx);
475  m_reportSectionDetail->insertGroupSection(idx - 1, rsdg);
476  rsdg->setGroupHeaderVisible(showgh);
477  rsdg->setGroupFooterVisible(showgf);
478  }
479 }
480 
481 
482 void KReportSectionEditor::brnMoveDown_clicked()
483 {
484  if (m_reportSectionDetail) {
485  int idx = m_ui.lbGroups->currentRow();
486  if (idx == (int)(m_ui.lbGroups->count() - 1)) return;
487  QString s = m_ui.lbGroups->currentItem()->text();
488  m_ui.lbGroups->takeItem(idx);
489  m_ui.lbGroups->insertItem (idx + 1, s);
490  m_ui.lbGroups->setCurrentRow(idx + 1, QItemSelectionModel::ClearAndSelect);
491  KReportDesignerSectionDetailGroup * rsdg = m_reportSectionDetail->groupSection(idx);
492  bool showgh = rsdg->groupHeaderVisible();
493  bool showgf = rsdg->groupFooterVisible();
494  m_reportSectionDetail->removeGroupSection(idx);
495  m_reportSectionDetail->insertGroupSection(idx + 1, rsdg);
496  rsdg->setGroupHeaderVisible(showgh);
497  rsdg->setGroupFooterVisible(showgf);
498  }
499 }
500 
501 void KReportSectionEditor::updateButtonsForItem(QListWidgetItem* currentItem)
502 {
503  const bool isItemSelected = currentItem;
504 
505  m_btnEdit->setEnabled(isItemSelected);
506  m_btnRemove->setEnabled(isItemSelected);
507 }
508 
509 void KReportSectionEditor::updateButtonsForRow(int row)
510 {
511  const bool enableMoveUpButton = (row > 0);
512  const bool enableMoveDownButton = (0 <= row) && (row+1 < m_ui.lbGroups->count());
513 
514  m_btnMoveUp->setEnabled(enableMoveUpButton);
515  m_btnMoveDown->setEnabled(enableMoveDownButton);
516 }
517 
518 void KReportSectionEditor::updateAddButton()
519 {
520  // search for unused column
521  bool foundUnusedColumn = false;
522  const QStringList keys = m_reportDesigner->fieldKeys();
523  const QSet<QString> columns = groupingColumns();
524  foreach(const QString &key, keys) {
525  // skip any editor helper fields
526  if (isEditorHelperField(key)) {
527  continue;
528  }
529  if (! columns.contains(key)) {
530  foundUnusedColumn = true;
531  break;
532  }
533  }
534  m_btnAdd->setEnabled(foundUnusedColumn);
535 }
KReportDesignerSectionDetail * detailSection() const
Return a pointer to the detail section.
UserRole
QWidget(QWidget *parent, Qt::WindowFlags f)
void setShortcut(const QKeySequence &key)
A section group allows a header and footer to be used for a particular report field.
int count(const T &value) const const
AscendingOrder
QIcon fromTheme(const QString &name)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
virtual void setData(int role, const QVariant &value)
char * toString(const T &value)
bool isEmpty() const const
const T & at(int i) const const
Key_Return
int indexOf(QStringView str, int from) const const
bool contains(const T &value) const const
QPushButton * button(QDialogButtonBox::StandardButton which) const const
QSet::iterator insert(const T &value)
void setDefault(bool)
The ReportDesigner is the main widget for designing a report.
QString tr(const char *sourceText, const char *disambiguation, int n)
T value(int i) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Feb 7 2023 04:17:37 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.