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