00001
00002
00003
00004
00005
00006 #include <fstream>
00007
00008 #include <Wt/WApplication>
00009 #include <Wt/WComboBox>
00010 #include <Wt/WContainerWidget>
00011 #include <Wt/WDatePicker>
00012 #include <Wt/WDateValidator>
00013 #include <Wt/WDialog>
00014 #include <Wt/WImage>
00015 #include <Wt/WIntValidator>
00016 #include <Wt/WItemDelegate>
00017 #include <Wt/WLabel>
00018 #include <Wt/WLineEdit>
00019 #include <Wt/WMessageBox>
00020 #include <Wt/WPushButton>
00021 #include <Wt/WRegExpValidator>
00022 #include <Wt/WGridLayout>
00023 #include <Wt/WPopupMenu>
00024 #include <Wt/WSortFilterProxyModel>
00025 #include <Wt/WStandardItem>
00026 #include <Wt/WStandardItemModel>
00027 #include <Wt/WTreeView>
00028 #include <Wt/WText>
00029 #include <Wt/WVBoxLayout>
00030
00031 #include <Wt/Chart/WPieChart>
00032
00033 #include "CsvUtil.h"
00034 #include "FolderView.h"
00035
00036 using namespace Wt;
00037
00042
00050 class FileModel : public WStandardItemModel
00051 {
00052 public:
00055 FileModel(WObject *parent)
00056 : WStandardItemModel(parent) { }
00057
00060 virtual std::string mimeType() const {
00061 return FolderView::FileSelectionMimeType;
00062 }
00063
00065 static WString dateDisplayFormat;
00066
00068 static WString dateEditFormat;
00069 };
00070
00071 WString FileModel::dateDisplayFormat(WString::fromUTF8("MMM dd, yyyy"));
00072 WString FileModel::dateEditFormat(WString::fromUTF8("dd-MM-yyyy"));
00073
00077 class FileEditDialog : public WDialog
00078 {
00079 public:
00080 FileEditDialog(WAbstractItemModel *model, const WModelIndex& item)
00081 : WDialog("Edit..."),
00082 model_(model),
00083 item_(item)
00084 {
00085 int modelRow = item_.row();
00086
00087 resize(300, WLength::Auto);
00088
00089
00090
00091
00092
00093
00094 nameEdit_ = new WLineEdit(asString(model_->data(modelRow, 1)));
00095
00096
00097 typeEdit_ = new WComboBox();
00098 typeEdit_->addItem("Document");
00099 typeEdit_->addItem("Spreadsheet");
00100 typeEdit_->addItem("Presentation");
00101 typeEdit_->setCurrentIndex
00102 (typeEdit_->findText(asString(model_->data(modelRow, 2))));
00103
00104
00105 sizeEdit_ = new WLineEdit(asString(model_->data(modelRow, 3)));
00106 sizeEdit_->setValidator
00107 (new WIntValidator(0, std::numeric_limits<int>::max(), this));
00108
00109
00110 createdPicker_ = new WDatePicker();
00111 createdPicker_->lineEdit()->validator()->setMandatory(true);
00112 createdPicker_->setFormat(FileModel::dateEditFormat);
00113 createdPicker_->setDate(boost::any_cast<WDate>(model_->data(modelRow, 4)));
00114
00115
00116 modifiedPicker_ = new WDatePicker();
00117 modifiedPicker_->lineEdit()->validator()->setMandatory(true);
00118 modifiedPicker_->setFormat(FileModel::dateEditFormat);
00119 modifiedPicker_->setDate(boost::any_cast<WDate>(model_->data(modelRow, 5)));
00120
00121
00122
00123
00124 WGridLayout *layout = new WGridLayout();
00125
00126 WLabel *l;
00127 int row = 0;
00128
00129 layout->addWidget(l = new WLabel("Name:"), row, 0);
00130 layout->addWidget(nameEdit_, row, 1);
00131 l->setBuddy(nameEdit_);
00132 ++row;
00133
00134 layout->addWidget(l = new WLabel("Type:"), row, 0);
00135 layout->addWidget(typeEdit_, row, 1, AlignTop);
00136 l->setBuddy(typeEdit_);
00137 ++row;
00138
00139 layout->addWidget(l = new WLabel("Size:"), row, 0);
00140 layout->addWidget(sizeEdit_, row, 1);
00141 l->setBuddy(sizeEdit_);
00142 ++row;
00143
00144 layout->addWidget(l = new WLabel("Created:"), row, 0);
00145 layout->addWidget(createdPicker_->lineEdit(), row, 1);
00146 layout->addWidget(createdPicker_, row, 2);
00147 l->setBuddy(createdPicker_->lineEdit());
00148 ++row;
00149
00150 layout->addWidget(l = new WLabel("Modified:"), row, 0);
00151 layout->addWidget(modifiedPicker_->lineEdit(), row, 1);
00152 layout->addWidget(modifiedPicker_, row, 2);
00153 l->setBuddy(modifiedPicker_->lineEdit());
00154 ++row;
00155
00156 WPushButton *b;
00157 WContainerWidget *buttons = new WContainerWidget();
00158 buttons->addWidget(b = new WPushButton("Save"));
00159 b->clicked().connect(SLOT(this, WDialog::accept));
00160 contents()->enterPressed().connect(SLOT(this, WDialog::accept));
00161 buttons->addWidget(b = new WPushButton("Cancel"));
00162 b->clicked().connect(SLOT(this, WDialog::reject));
00163
00164
00165
00166
00167 switch (item.column()) {
00168 case 2:
00169 typeEdit_->setFocus(); break;
00170 case 3:
00171 sizeEdit_->setFocus(); break;
00172 case 4:
00173 createdPicker_->lineEdit()->setFocus(); break;
00174 case 5:
00175 modifiedPicker_->lineEdit()->setFocus(); break;
00176 default:
00177 nameEdit_->setFocus(); break;
00178 }
00179
00180 layout->addWidget(buttons, row, 0, 0, 3, AlignCenter);
00181 layout->setColumnStretch(1, 1);
00182
00183 contents()->setLayout(layout, AlignTop | AlignJustify);
00184
00185 finished().connect(SLOT(this, FileEditDialog::handleFinish));
00186
00187 show();
00188 }
00189
00190 private:
00191 WAbstractItemModel *model_;
00192 WModelIndex item_;
00193
00194 WLineEdit *nameEdit_, *sizeEdit_;
00195 WComboBox *typeEdit_;
00196 WDatePicker *createdPicker_, *modifiedPicker_;
00197
00198 void handleFinish(DialogCode result)
00199 {
00200 if (result == WDialog::Accepted) {
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 WAbstractItemModel *m = model_;
00212 int modelRow = item_.row();
00213
00214 WAbstractProxyModel *proxyModel = dynamic_cast<WAbstractProxyModel *>(m);
00215 if (proxyModel) {
00216 m = proxyModel->sourceModel();
00217 modelRow = proxyModel->mapToSource(item_).row();
00218 }
00219
00220 m->setData(modelRow, 1, boost::any(nameEdit_->text()));
00221 m->setData(modelRow, 2, boost::any(typeEdit_->currentText()));
00222 m->setData(modelRow, 3, boost::any(boost::lexical_cast<int>
00223 (sizeEdit_->text().toUTF8())));
00224 m->setData(modelRow, 4, boost::any(createdPicker_->date()));
00225 m->setData(modelRow, 5, boost::any(modifiedPicker_->date()));
00226 }
00227
00228 delete this;
00229 }
00230
00231 };
00232
00236 class TreeViewDragDrop : public WApplication
00237 {
00238 public:
00241 TreeViewDragDrop(const WEnvironment &env)
00242 : WApplication(env),
00243 popup_(0),
00244 popupActionBox_(0)
00245 {
00246
00247
00248
00249 folderModel_ = new WStandardItemModel(0, 1, this);
00250 populateFolders();
00251
00252 fileModel_ = new FileModel(this);
00253 populateFiles();
00254
00255 fileFilterModel_ = new WSortFilterProxyModel(this);
00256 fileFilterModel_->setSourceModel(fileModel_);
00257 fileFilterModel_->setDynamicSortFilter(true);
00258 fileFilterModel_->setFilterKeyColumn(0);
00259 fileFilterModel_->setFilterRole(UserRole);
00260
00261
00262
00263
00264 createUI();
00265 }
00266
00267 virtual ~TreeViewDragDrop() {
00268 delete popup_;
00269 delete popupActionBox_;
00270 }
00271
00272 private:
00274 WStandardItemModel *folderModel_;
00275
00277 WStandardItemModel *fileModel_;
00278
00280 WSortFilterProxyModel *fileFilterModel_;
00281
00283 std::map<std::string, WString> folderNameMap_;
00284
00286 WTreeView *folderView_;
00287
00289 WTreeView *fileView_;
00290
00292 WPopupMenu *popup_;
00293
00295 WMessageBox *popupActionBox_;
00296
00299 void createUI() {
00300 WContainerWidget *w = root();
00301 w->setStyleClass("maindiv");
00302
00303
00304
00305
00306 WGridLayout *layout = new WGridLayout();
00307 layout->addWidget(createTitle("Folders"), 0, 0);
00308 layout->addWidget(createTitle("Files"), 0, 1);
00309 layout->addWidget(folderView(), 1, 0);
00310
00311
00312 folderView_->select(folderModel_->index(0, 0, folderModel_->index(0, 0)));
00313
00314 WVBoxLayout *vbox = new WVBoxLayout();
00315 vbox->addWidget(fileView(), 1);
00316 vbox->addWidget(pieChart(), 0);
00317
00318 layout->addLayout(vbox, 1, 1);
00319
00320 layout->addWidget(aboutDisplay(), 2, 0, 1, 2, AlignTop);
00321
00322
00323
00324
00325 layout->setRowStretch(1, 1);
00326 layout->setColumnStretch(1, 1);
00327
00328 w->setLayout(layout);
00329 }
00330
00333 WText *createTitle(const WString& title) {
00334 WText *result = new WText(title);
00335 result->setInline(false);
00336 result->setStyleClass("title");
00337
00338 return result;
00339 }
00340
00343 WTreeView *folderView() {
00344 WTreeView *treeView = new FolderView();
00345
00346
00347
00348
00349
00350
00351
00352
00353 treeView->setAttributeValue
00354 ("oncontextmenu",
00355 "event.cancelBubble = true; event.returnValue = false; return false;");
00356 treeView->setModel(folderModel_);
00357 treeView->resize(200, WLength::Auto);
00358 treeView->setSelectionMode(SingleSelection);
00359 treeView->expandToDepth(1);
00360 treeView->selectionChanged().connect(SLOT(this,
00361 TreeViewDragDrop::folderChanged));
00362
00363 treeView->mouseWentDown().connect(SLOT(this, TreeViewDragDrop::showPopup));
00364
00365 folderView_ = treeView;
00366
00367 return treeView;
00368 }
00369
00372 WTreeView *fileView() {
00373 WTreeView *treeView = new WTreeView();
00374
00375
00376
00377 treeView->setRootIsDecorated(false);
00378 treeView->setAlternatingRowColors(true);
00379
00380 treeView->setModel(fileFilterModel_);
00381 treeView->setSelectionMode(ExtendedSelection);
00382 treeView->setDragEnabled(true);
00383
00384
00385 treeView->setColumnWidth(1, 150);
00386 treeView->setColumnWidth(2, 100);
00387 treeView->setColumnWidth(3, 60);
00388 treeView->setColumnWidth(4, 100);
00389 treeView->setColumnWidth(5, 100);
00390
00391 WItemDelegate *delegate = new WItemDelegate(this);
00392 delegate->setTextFormat(FileModel::dateDisplayFormat);
00393 treeView->setItemDelegateForColumn(4, delegate);
00394 treeView->setItemDelegateForColumn(5, delegate);
00395
00396 treeView->setColumnAlignment(3, AlignRight);
00397 treeView->setColumnAlignment(4, AlignRight);
00398 treeView->setColumnAlignment(5, AlignRight);
00399
00400 treeView->sortByColumn(1, AscendingOrder);
00401
00402 treeView->doubleClicked().connect(SLOT(this, TreeViewDragDrop::editFile));
00403
00404 fileView_ = treeView;
00405
00406 return treeView;
00407 }
00408
00411 void editFile(const WModelIndex& item) {
00412 new FileEditDialog(fileView_->model(), item);
00413 }
00414
00417 WWidget *pieChart() {
00418 using namespace Chart;
00419
00420 WPieChart *chart = new WPieChart();
00421 chart->resize(450, 200);
00422 chart->setModel(fileFilterModel_);
00423 chart->setTitle("File sizes");
00424
00425 chart->setLabelsColumn(1);
00426 chart->setDataColumn(3);
00427
00428 chart->setPerspectiveEnabled(true, 0.2);
00429 chart->setDisplayLabels(Outside | TextLabel);
00430
00431 WContainerWidget *w = new WContainerWidget();
00432 w->setContentAlignment(AlignCenter);
00433 w->setStyleClass("about");
00434 w->addWidget(chart);
00435
00436 return w;
00437 }
00438
00441 WWidget *aboutDisplay() {
00442 WText *result = new WText(WString::tr("about-text"));
00443 result->setStyleClass("about");
00444 return result;
00445 }
00446
00450 void folderChanged() {
00451 if (folderView_->selectedIndexes().empty())
00452 return;
00453
00454 WModelIndex selected = *folderView_->selectedIndexes().begin();
00455 boost::any d = selected.data(UserRole);
00456 if (!d.empty()) {
00457 std::string folder = boost::any_cast<std::string>(d);
00458
00459
00460
00461
00462
00463 fileFilterModel_->setFilterRegExp(folder);
00464 }
00465 }
00466
00469 void showPopup(const WModelIndex& item, const WMouseEvent& event) {
00470 if (event.button() == WMouseEvent::RightButton) {
00471
00472 if (!folderView_->isSelected(item))
00473 folderView_->select(item);
00474
00475 delete popup_;
00476
00477 popup_ = new WPopupMenu();
00478 popup_->addItem("icons/folder_new.gif", "Create a New Folder");
00479 popup_->addItem("Rename this Folder")->setCheckable(true);
00480 popup_->addItem("Delete this Folder");
00481 popup_->addSeparator();
00482 popup_->addItem("Folder Details");
00483 popup_->addSeparator();
00484 popup_->addItem("Application Inventory");
00485 popup_->addItem("Hardware Inventory");
00486 popup_->addSeparator();
00487
00488 WPopupMenu *subMenu = new WPopupMenu();
00489 subMenu->addItem("Sub Item 1");
00490 subMenu->addItem("Sub Item 2");
00491 popup_->addMenu("File Deployments", subMenu);
00492
00493
00494
00495
00496
00497
00498
00499
00500 popup_->aboutToHide().connect(SLOT(this, TreeViewDragDrop::popupAction));
00501 popup_->popup(event);
00502 }
00503 }
00504
00507 void popupAction() {
00508 if (popup_->result()) {
00509
00510
00511
00512
00513 WString text = popup_->result()->text();
00514 delete popup_;
00515 popup_ = 0;
00516
00517 popupActionBox_ = new WMessageBox("Sorry.","Action '" + text
00518 + "' is not implemented.", NoIcon, Ok);
00519 popupActionBox_->buttonClicked()
00520 .connect(SLOT(this, TreeViewDragDrop::dialogDone));
00521 popupActionBox_->show();
00522 } else {
00523 delete popup_;
00524 popup_ = 0;
00525 }
00526 }
00527
00530 void dialogDone() {
00531 delete popupActionBox_;
00532 popupActionBox_ = 0;
00533 }
00534
00542 void populateFiles() {
00543 fileModel_->invisibleRootItem()->setRowCount(0);
00544
00545 std::ifstream f("data/files.csv");
00546 readFromCsv(f, fileModel_);
00547
00548 for (int i = 0; i < fileModel_->rowCount(); ++i) {
00549 WStandardItem *item = fileModel_->item(i, 0);
00550 item->setFlags(item->flags() | ItemIsDragEnabled);
00551 item->setIcon("icons/file.gif");
00552
00553 std::string folderId = item->text().toUTF8();
00554
00555 item->setData(boost::any(folderId), UserRole);
00556 item->setText(folderNameMap_[folderId]);
00557
00558 convertToDate(fileModel_->item(i, 4));
00559 convertToDate(fileModel_->item(i, 5));
00560 }
00561 }
00562
00565 void convertToDate(WStandardItem *item) {
00566 WDate d = WDate::fromString(item->text(), FileModel::dateEditFormat);
00567 item->setData(boost::any(d), DisplayRole);
00568 }
00569
00572 void populateFolders() {
00573 WStandardItem *level1, *level2;
00574
00575 folderModel_->appendRow(level1 = createFolderItem("San Fransisco"));
00576 level1->appendRow(level2 = createFolderItem("Investors", "sf-investors"));
00577 level1->appendRow(level2 = createFolderItem("Fellows", "sf-fellows"));
00578
00579 folderModel_->appendRow(level1 = createFolderItem("Sophia Antipolis"));
00580 level1->appendRow(level2 = createFolderItem("R&D", "sa-r_d"));
00581 level1->appendRow(level2 = createFolderItem("Services", "sa-services"));
00582 level1->appendRow(level2 = createFolderItem("Support", "sa-support"));
00583 level1->appendRow(level2 = createFolderItem("Billing", "sa-billing"));
00584
00585 folderModel_->appendRow(level1 = createFolderItem("New York"));
00586 level1->appendRow(level2 = createFolderItem("Marketing", "ny-marketing"));
00587 level1->appendRow(level2 = createFolderItem("Sales", "ny-sales"));
00588 level1->appendRow(level2 = createFolderItem("Advisors", "ny-advisors"));
00589
00590 folderModel_->appendRow(level1 = createFolderItem
00591 (WString::fromUTF8("Frankfürt")));
00592 level1->appendRow(level2 = createFolderItem("Sales", "frank-sales"));
00593
00594 folderModel_->setHeaderData(0, Horizontal,
00595 boost::any(std::string("SandBox")));
00596 }
00597
00602 WStandardItem *createFolderItem(const WString& location,
00603 const std::string& folderId = std::string())
00604 {
00605 WStandardItem *result = new WStandardItem(location);
00606
00607 if (!folderId.empty()) {
00608 result->setData(boost::any(folderId));
00609 result->setFlags(result->flags() | ItemIsDropEnabled);
00610 folderNameMap_[folderId] = location;
00611 } else
00612 result->setFlags(result->flags().clear(ItemIsSelectable));
00613
00614 result->setIcon("icons/folder.gif");
00615
00616 return result;
00617 }
00618
00619 };
00620
00621 WApplication *createApplication(const WEnvironment& env)
00622 {
00623 WApplication *app = new TreeViewDragDrop(env);
00624 app->setTwoPhaseRenderingThreshold(0);
00625 app->setTitle("WTreeView Drag & Drop");
00626 app->useStyleSheet("styles.css");
00627 app->messageResourceBundle().use("about");
00628 app->refresh();
00629
00630 return app;
00631 }
00632
00633 int main(int argc, char **argv)
00634 {
00635 return WRun(argc, argv, &createApplication);
00636 }
00637