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/WLabel>
00017 #include <Wt/WLineEdit>
00018 #include <Wt/WMessageBox>
00019 #include <Wt/WPushButton>
00020 #include <Wt/WRegExpValidator>
00021 #include <Wt/WGridLayout>
00022 #include <Wt/WPopupMenu>
00023 #include <Wt/WSortFilterProxyModel>
00024 #include <Wt/WStandardItem>
00025 #include <Wt/WStandardItemModel>
00026 #include <Wt/WTreeView>
00027 #include <Wt/WText>
00028
00029 #include "CsvUtil.h"
00030 #include "FolderView.h"
00031
00032 using namespace Wt;
00033
00038
00046 class FileModel : public WStandardItemModel
00047 {
00048 public:
00051 FileModel(WObject *parent)
00052 : WStandardItemModel(parent) { }
00053
00056 virtual std::string mimeType() const {
00057 return FolderView::FileSelectionMimeType;
00058 }
00059
00061 static WString dateDisplayFormat;
00062
00064 static WString dateEditFormat;
00065 };
00066
00067 WString FileModel::dateDisplayFormat("MMM dd, yyyy");
00068 WString FileModel::dateEditFormat("dd-MM-yyyy");
00069
00075 class FileView : public WTreeView
00076 {
00077 public:
00080 FileView(WContainerWidget *parent = 0)
00081 : WTreeView(parent)
00082 {
00083 doubleClicked.connect(SLOT(this, FileView::edit));
00084 }
00085
00086 private:
00089 void edit(const WModelIndex& item) {
00090 int modelRow = item.row();
00091
00092 WDialog d("Edit...");
00093 d.resize(300, WLength());
00094
00095
00096
00097
00098
00099
00100 WLineEdit *nameEdit = new WLineEdit(asString(model()->data(modelRow, 1)));
00101
00102
00103 WComboBox *typeEdit = new WComboBox();
00104 typeEdit->addItem("Document");
00105 typeEdit->addItem("Spreadsheet");
00106 typeEdit->addItem("Presentation");
00107 typeEdit->setCurrentIndex
00108 (typeEdit->findText(asString(model()->data(modelRow, 2))));
00109
00110
00111 WLineEdit *sizeEdit
00112 = new WLineEdit(asString(model()->data(modelRow, 3)));
00113 sizeEdit->setValidator
00114 (new WIntValidator(0, std::numeric_limits<int>::max(), this));
00115
00116
00117 WLineEdit *createdEdit = new WLineEdit();
00118 createdEdit->setValidator
00119 (new WDateValidator(FileModel::dateEditFormat, this));
00120 createdEdit->validator()->setMandatory(true);
00121
00122 WDatePicker *createdPicker
00123 = new WDatePicker(new WImage("icons/calendar_edit.png"), createdEdit);
00124 createdPicker->setFormat(FileModel::dateEditFormat);
00125 createdPicker->setDate(boost::any_cast<WDate>(model()->data(modelRow, 4)));
00126
00127
00128 WLineEdit *modifiedEdit = new WLineEdit();
00129 modifiedEdit->setValidator
00130 (new WDateValidator(FileModel::dateEditFormat, this));
00131 modifiedEdit->validator()->setMandatory(true);
00132
00133 WDatePicker *modifiedPicker
00134 = new WDatePicker(new WImage("icons/calendar_edit.png"), modifiedEdit);
00135 modifiedPicker->setFormat(FileModel::dateEditFormat);
00136 modifiedPicker->setDate(boost::any_cast<WDate>(model()->data(modelRow, 5)));
00137
00138
00139
00140
00141 WGridLayout *layout = new WGridLayout();
00142
00143 WLabel *l;
00144 int row = 0;
00145
00146 layout->addWidget(l = new WLabel("Name:"), row, 0);
00147 layout->addWidget(nameEdit, row, 1);
00148 l->setBuddy(nameEdit);
00149 ++row;
00150
00151 layout->addWidget(l = new WLabel("Type:"), row, 0);
00152 layout->addWidget(typeEdit, row, 1, AlignTop);
00153 l->setBuddy(typeEdit);
00154 ++row;
00155
00156 layout->addWidget(l = new WLabel("Size:"), row, 0);
00157 layout->addWidget(sizeEdit, row, 1);
00158 l->setBuddy(sizeEdit);
00159 ++row;
00160
00161 layout->addWidget(l = new WLabel("Created:"), row, 0);
00162 layout->addWidget(createdEdit, row, 1);
00163 layout->addWidget(createdPicker, row, 2);
00164 l->setBuddy(createdEdit);
00165 ++row;
00166
00167 layout->addWidget(l = new WLabel("Modified:"), row, 0);
00168 layout->addWidget(modifiedEdit, row, 1);
00169 layout->addWidget(modifiedPicker, row, 2);
00170 l->setBuddy(modifiedEdit);
00171 ++row;
00172
00173 WPushButton *b;
00174 WContainerWidget *buttons = new WContainerWidget();
00175 buttons->addWidget(b = new WPushButton("Save"));
00176 b->clicked.connect(SLOT(&d, WDialog::accept));
00177 d.contents()->enterPressed.connect(SLOT(&d, WDialog::accept));
00178 buttons->addWidget(b = new WPushButton("Cancel"));
00179 b->clicked.connect(SLOT(&d, WDialog::reject));
00180
00181
00182
00183
00184 switch (item.column()) {
00185 case 2:
00186 typeEdit->setFocus(); break;
00187 case 3:
00188 sizeEdit->setFocus(); break;
00189 case 4:
00190 createdEdit->setFocus(); break;
00191 case 5:
00192 modifiedEdit->setFocus(); break;
00193 default:
00194 nameEdit->setFocus(); break;
00195 }
00196
00197 layout->addWidget(buttons, row, 0, 0, 2, AlignCenter);
00198 layout->setColumnStretch(1, 1);
00199
00200 d.contents()->setLayout(layout, AlignTop | AlignJustify);
00201
00202 if (d.exec() == WDialog::Accepted) {
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 WAbstractItemModel *m = model();
00214
00215 WAbstractProxyModel *proxyModel = dynamic_cast<WAbstractProxyModel *>(m);
00216 if (proxyModel) {
00217 m = proxyModel->sourceModel();
00218 modelRow = proxyModel->mapToSource(item).row();
00219 }
00220
00221 m->setData(modelRow, 1, boost::any(nameEdit->text()));
00222 m->setData(modelRow, 2, boost::any(typeEdit->currentText()));
00223 m->setData(modelRow, 3, boost::any(boost::lexical_cast<int>
00224 (sizeEdit->text().toUTF8())));
00225 m->setData(modelRow, 4, boost::any(createdPicker->date()));
00226 m->setData(modelRow, 5, boost::any(modifiedPicker->date()));
00227 }
00228 }
00229 };
00230
00234 class TreeViewDragDrop : public WApplication
00235 {
00236 public:
00239 TreeViewDragDrop(const WEnvironment &env)
00240 : WApplication(env) {
00241
00242
00243
00244
00245 folderModel_ = new WStandardItemModel(0, 1, this);
00246 populateFolders();
00247
00248 fileModel_ = new FileModel(this);
00249 populateFiles();
00250
00251 fileFilterModel_ = new WSortFilterProxyModel(this);
00252 fileFilterModel_->setSourceModel(fileModel_);
00253 fileFilterModel_->setDynamicSortFilter(true);
00254 fileFilterModel_->setFilterKeyColumn(0);
00255 fileFilterModel_->setFilterRole(UserRole);
00256
00257
00258
00259
00260 createUI();
00261
00262
00263
00264
00265 folderView_->select
00266 (folderModel_->index(0, 0, folderModel_->index(0, 0)));
00267 }
00268
00269 private:
00271 WStandardItemModel *folderModel_;
00272
00274 WStandardItemModel *fileModel_;
00275
00277 WSortFilterProxyModel *fileFilterModel_;
00278
00280 std::map<std::string, WString> folderNameMap_;
00281
00283 WTreeView *folderView_;
00284
00286 WTreeView *fileView_;
00287
00290 void createUI() {
00291 WContainerWidget *w = root();
00292 w->setStyleClass("maindiv");
00293
00294
00295
00296
00297 WGridLayout *layout = new WGridLayout();
00298 layout->addWidget(createTitle("Folders"), 0, 0);
00299 layout->addWidget(createTitle("Files"), 0, 1);
00300 layout->addWidget(folderView(), 1, 0);
00301 layout->addWidget(fileView(), 1, 1);
00302
00303 layout->addWidget(aboutDisplay(), 2, 0, 1, 2, AlignTop);
00304
00305
00306
00307
00308 layout->setRowStretch(1, 1);
00309 layout->setColumnStretch(1, 1);
00310
00311 w->setLayout(layout);
00312 }
00313
00316 WText *createTitle(const WString& title) {
00317 WText *result = new WText(title);
00318 result->setInline(false);
00319 result->setStyleClass("title");
00320
00321 return result;
00322 }
00323
00326 WTreeView *folderView() {
00327 WTreeView *treeView = new FolderView();
00328
00329
00330
00331
00332
00333
00334
00335
00336 treeView->setAttributeValue
00337 ("oncontextmenu",
00338 "event.cancelBubble = true; event.returnValue = false; return false;");
00339 treeView->setModel(folderModel_);
00340 treeView->resize(200, WLength::Auto);
00341 treeView->setSelectionMode(SingleSelection);
00342 treeView->expandToDepth(1);
00343 treeView->selectionChanged.connect(SLOT(this,
00344 TreeViewDragDrop::folderChanged));
00345
00346 treeView->mouseWentDown.connect(SLOT(this, TreeViewDragDrop::showPopup));
00347
00348 folderView_ = treeView;
00349
00350 return treeView;
00351 }
00352
00355 WTreeView *fileView() {
00356 WTreeView *treeView = new FileView();
00357
00358
00359
00360 treeView->setRootIsDecorated(false);
00361
00362 treeView->setModel(fileFilterModel_);
00363 treeView->setSelectionMode(ExtendedSelection);
00364 treeView->setDragEnabled(true);
00365
00366 treeView->setColumnWidth(0, 100);
00367 treeView->setColumnWidth(1, 150);
00368 treeView->setColumnWidth(2, 100);
00369 treeView->setColumnWidth(3, 80);
00370 treeView->setColumnWidth(4, 120);
00371 treeView->setColumnWidth(5, 120);
00372
00373 treeView->setColumnFormat(4, FileModel::dateDisplayFormat);
00374 treeView->setColumnFormat(5, FileModel::dateDisplayFormat);
00375
00376 treeView->setColumnAlignment(3, AlignRight);
00377 treeView->setColumnAlignment(4, AlignRight);
00378 treeView->setColumnAlignment(5, AlignRight);
00379
00380 treeView->sortByColumn(1, AscendingOrder);
00381
00382 fileView_ = treeView;
00383
00384 return treeView;
00385 }
00386
00389 WWidget *aboutDisplay() {
00390 WText *result = new WText(WString::tr("about-text"));
00391 result->setStyleClass("about");
00392 return result;
00393 }
00394
00398 void folderChanged() {
00399 if (folderView_->selectedIndexes().empty())
00400 return;
00401
00402 WModelIndex selected = *folderView_->selectedIndexes().begin();
00403 boost::any d = selected.data(UserRole);
00404 if (!d.empty()) {
00405 std::string folder = boost::any_cast<std::string>(d);
00406
00407
00408
00409
00410
00411 fileFilterModel_->setFilterRegExp(folder);
00412 }
00413 }
00414
00417 void showPopup(const WModelIndex& item, const WMouseEvent& event) {
00418 if (event.button() == WMouseEvent::RightButton) {
00419
00420
00421 folderView_->select(item);
00422
00423 WPopupMenu popup;
00424 popup.addItem("icons/folder_new.gif", "Create a New Folder");
00425 popup.addItem("Rename this Folder")->setCheckable(true);
00426 popup.addItem("Delete this Folder");
00427 popup.addSeparator();
00428 popup.addItem("Folder Details");
00429 popup.addSeparator();
00430 popup.addItem("Application Inventory");
00431 popup.addItem("Hardware Inventory");
00432 popup.addSeparator();
00433
00434 WPopupMenu *subMenu = new WPopupMenu();
00435 subMenu->addItem("Sub Item 1");
00436 subMenu->addItem("Sub Item 2");
00437 popup.addMenu("File Deployments", subMenu);
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 WPopupMenuItem *item = popup.exec(event);
00448
00449 if (item) {
00450
00451
00452
00453
00454 WMessageBox::show("Sorry.",
00455 "Action '" + item->text() + "' is not implemented.",
00456 Ok);
00457 }
00458 }
00459 }
00460
00468 void populateFiles() {
00469 fileModel_->invisibleRootItem()->setRowCount(0);
00470
00471 std::ifstream f("data/files.csv");
00472 readFromCsv(f, fileModel_);
00473
00474 for (int i = 0; i < fileModel_->rowCount(); ++i) {
00475 WStandardItem *item = fileModel_->item(i, 0);
00476 item->setFlags(item->flags() | ItemIsDragEnabled);
00477 item->setIcon("icons/file.gif");
00478
00479 std::string folderId = item->text().toUTF8();
00480
00481 item->setData(boost::any(folderId), UserRole);
00482 item->setText(folderNameMap_[folderId]);
00483
00484 convertToDate(fileModel_->item(i, 4));
00485 convertToDate(fileModel_->item(i, 5));
00486 }
00487 }
00488
00491 void convertToDate(WStandardItem *item) {
00492 WDate d = WDate::fromString(item->text(), FileModel::dateEditFormat);
00493 item->setData(boost::any(d), DisplayRole);
00494 }
00495
00498 void populateFolders() {
00499 WStandardItem *level1, *level2;
00500
00501 folderModel_->appendRow(level1 = createFolderItem("San Fransisco"));
00502 level1->appendRow(level2 = createFolderItem("Investors", "sf-investors"));
00503 level1->appendRow(level2 = createFolderItem("Fellows", "sf-fellows"));
00504
00505 folderModel_->appendRow(level1 = createFolderItem("Sophia Antipolis"));
00506 level1->appendRow(level2 = createFolderItem("R&D", "sa-r_d"));
00507 level1->appendRow(level2 = createFolderItem("Services", "sa-services"));
00508 level1->appendRow(level2 = createFolderItem("Support", "sa-support"));
00509 level1->appendRow(level2 = createFolderItem("Billing", "sa-billing"));
00510
00511 folderModel_->appendRow(level1 = createFolderItem("New York"));
00512 level1->appendRow(level2 = createFolderItem("Marketing", "ny-marketing"));
00513 level1->appendRow(level2 = createFolderItem("Sales", "ny-sales"));
00514 level1->appendRow(level2 = createFolderItem("Advisors", "ny-advisors"));
00515
00516 folderModel_->appendRow(level1 = createFolderItem
00517 (WString::fromUTF8("Frankfürt")));
00518 level1->appendRow(level2 = createFolderItem("Sales", "frank-sales"));
00519
00520 folderModel_->setHeaderData(0, Horizontal,
00521 boost::any(std::string("SandBox")));
00522 }
00523
00528 WStandardItem *createFolderItem(const WString& location,
00529 const std::string& folderId = std::string())
00530 {
00531 WStandardItem *result = new WStandardItem(location);
00532
00533 if (!folderId.empty()) {
00534 result->setData(boost::any(folderId));
00535 result->setFlags(result->flags() | ItemIsDropEnabled);
00536 folderNameMap_[folderId] = location;
00537 } else
00538 result->setFlags(result->flags() & ~ItemIsSelectable);
00539
00540 result->setIcon("icons/folder.gif");
00541
00542 return result;
00543 }
00544
00545 };
00546
00547 WApplication *createApplication(const WEnvironment& env)
00548 {
00549 WApplication *app = new TreeViewDragDrop(env);
00550 app->setTitle("WTreeView Drag & Drop");
00551 app->useStyleSheet("styles.css");
00552 app->messageResourceBundle().use("about");
00553 app->refresh();
00554
00555 return app;
00556 }
00557
00558 int main(int argc, char **argv)
00559 {
00560 return WRun(argc, argv, &createApplication);
00561 }
00562