1 #pragma once
2 #include <gtkmm.h>
3 
4 #include "helper.h"
5 #include "keychain.h"
6 
7 class ItemView : public Gtk::Grid {
8 public:
ItemView(const KeychainItem & data)9     ItemView(const KeychainItem& data) : Gtk::Grid() {
10         set_row_spacing(5);
11         set_column_spacing(3);
12         set_margin_end(5);
13         set_margin_start(5);
14 
15         if (data.sections.size() > 0) {
16             for (const auto& section : data.sections) {
17                 attachSectionTitle(section.first);
18                 for (const auto& field : section.second) {
19                     processSingleField(field);
20                 }
21             }
22         }
23 
24         if (!data.notes.empty()) {
25             attachSectionTitle("Notes");
26             auto notes_buffer = Gtk::TextBuffer::create();
27             notes_buffer->set_text(data.notes);
28 
29             auto notes_field = Gtk::manage(new Gtk::TextView(notes_buffer));
30             notes_field->set_hexpand(true);
31             notes_field->set_vexpand(true);
32             notes_field->set_editable(false);
33             notes_field->set_wrap_mode(Gtk::WRAP_WORD);
34             attach(*notes_field, 0, row_index++, 4, 1);
35         }
36 
37         if (data.URLs.size() > 0) {
38             attachSectionTitle("URLs");
39             for (auto& url : data.URLs) {
40                 auto url_button = Gtk::manage(new Gtk::LinkButton(url, url));
41                 attach(*url_button, 0, row_index++, 4, 1);
42             }
43         }
44 
45         show_all_children();
46     }
~ItemView()47     virtual ~ItemView() {}
48 
49 protected:
attachSectionTitle(std::string label)50     void attachSectionTitle(std::string label) {
51         auto label_widget = Gtk::manage(new Gtk::Label(label));
52         attach(*label_widget, 0, row_index++, 4, 1);
53     }
54 
processSingleField(const KeychainField & field)55     void processSingleField(const KeychainField& field) {
56         processSingleField(field.name, field.value, field.password);
57     }
58 
processSingleField(std::string label,std::string value,bool conceal)59     void processSingleField(std::string label, std::string value, bool conceal) {
60         auto my_index = row_index++;
61 
62         auto label_widget = Gtk::manage(new Gtk::Label(label));
63         label_widget->set_halign(Gtk::ALIGN_END);
64         label_widget->set_margin_end(5);
65         attach(*label_widget, 0, my_index, 1, 1);
66 
67         auto value_widget = Gtk::manage(new Gtk::Entry());
68         value_widget->set_hexpand(true);
69         value_widget->set_editable(false);
70 
71         const auto isTOTP = isTOTPURI(value);
72         if (isTOTP) {
73             try {
74                 value_widget->set_text(calculateTOTP(value));
75             } catch (std::exception& e) {
76                 errorDialog(e.what());
77             }
78         } else {
79             value_widget->set_text(value);
80         }
81 
82         if (conceal && !isTOTP)
83             value_widget->set_visibility(false);
84         attach(*value_widget, 1, my_index, conceal ? 1 : 3, 1);
85 
86         if (conceal) {
87             auto copy_button = Gtk::manage(new Gtk::Button("_Copy", true));
88             copy_button->signal_clicked().connect([value_widget]() {
89                 auto valueText = value_widget->get_text();
90                 auto clipboard = Gtk::Clipboard::get();
91                 clipboard->set_text(valueText);
92                 clipboard->store();
93             });
94             attach(*copy_button, 2, my_index, 1, 1);
95             if (isTOTP) {
96                 auto calculate_button = Gtk::manage(new Gtk::Button("_Calculate", true));
97                 calculate_button->signal_clicked().connect([value, value_widget]() {
98                     try {
99                         value_widget->set_text(calculateTOTP(value));
100                     } catch (std::exception& e) {
101                         errorDialog(e.what());
102                     }
103                 });
104                 attach(*calculate_button, 3, my_index, 1, 1);
105             } else {
106                 auto reveal_button = Gtk::manage(new Gtk::Button("_Reveal", true));
107                 reveal_button->signal_clicked().connect([reveal_button, value_widget]() {
108                     bool visible = value_widget->get_visibility();
109                     visible = !visible;
110 
111                     value_widget->set_visibility(visible);
112                     reveal_button->set_label(visible ? "_Hide" : "_Reveal");
113                 });
114                 attach(*reveal_button, 3, my_index, 1, 1);
115             }
116         }
117     }
118     int row_index = 0;
119 };
120