1 /* main_window_layout.cpp 2 * 3 * Wireshark - Network traffic analyzer 4 * By Gerald Combs <gerald@wireshark.org> 5 * Copyright 1998 Gerald Combs 6 * 7 * SPDX-License-Identifier: GPL-2.0-or-later 8 */ 9 10 #include <config.h> 11 12 #include <ui/qt/main_window.h> 13 #include <ui/qt/widgets/additional_toolbar.h> 14 15 #include "ui/recent.h" 16 17 #include "epan/prefs.h" 18 19 #include <QSplitter> 20 #include <QVector> 21 #include <QList> 22 #include <QWidget> 23 #include <QRect> 24 #include <QAction> 25 #include <QToolBar> 26 27 #include <ui/qt/byte_view_tab.h> 28 #include <ui/qt/packet_list.h> 29 #include <ui/qt/packet_diagram.h> 30 #include <ui/qt/proto_tree.h> 31 32 #include <wsutil/ws_assert.h> 33 34 /* 35 * The generated Ui_MainWindow::setupUi() can grow larger than our configured limit, 36 * so turn off -Wframe-larger-than= for ui_main_window.h. 37 */ 38 DIAG_OFF(frame-larger-than=) 39 #include <ui_main_window.h> 40 DIAG_ON(frame-larger-than=) 41 showWelcome()42void MainWindow::showWelcome() 43 { 44 main_ui_->mainStack->setCurrentWidget(welcome_page_); 45 } 46 showCapture()47void MainWindow::showCapture() 48 { 49 main_ui_->mainStack->setCurrentWidget(&master_split_); 50 } 51 getLayoutWidget(layout_pane_content_e type)52QWidget* MainWindow::getLayoutWidget(layout_pane_content_e type) { 53 switch (type) { 54 case layout_pane_content_none: 55 return &empty_pane_; 56 case layout_pane_content_plist: 57 return packet_list_; 58 case layout_pane_content_pdetails: 59 return proto_tree_; 60 case layout_pane_content_pbytes: 61 return byte_view_tab_; 62 case layout_pane_content_pdiagram: 63 return packet_diagram_; 64 default: 65 ws_assert_not_reached(); 66 return NULL; 67 } 68 } 69 70 71 // A new layout should be applied when it differs from the old layout AND 72 // at the following times: 73 // - At startup 74 // - When the preferences change 75 // - When the profile changes layoutPanes()76void MainWindow::layoutPanes() 77 { 78 QVector<unsigned> new_layout = QVector<unsigned>() << prefs.gui_layout_type 79 << prefs.gui_layout_content_1 80 << prefs.gui_layout_content_2 81 << prefs.gui_layout_content_3 82 << recent.packet_list_show 83 << recent.tree_view_show 84 << recent.byte_view_show 85 << recent.packet_diagram_show; 86 87 if (cur_layout_ == new_layout) return; 88 89 QSplitter *parents[3]; 90 91 // Reparent all widgets and add them back in the proper order below. 92 // This hides each widget as well. 93 packet_list_->freeze(); // Clears tree, byte view tabs, and diagram. 94 packet_list_->setParent(main_ui_->mainStack); 95 proto_tree_->setParent(main_ui_->mainStack); 96 byte_view_tab_->setParent(main_ui_->mainStack); 97 packet_diagram_->setParent(main_ui_->mainStack); 98 empty_pane_.setParent(main_ui_->mainStack); 99 extra_split_.setParent(main_ui_->mainStack); 100 101 // XXX We should try to preserve geometries if we can, e.g. by 102 // checking to see if the layout type is the same. 103 switch(prefs.gui_layout_type) { 104 case(layout_type_2): 105 case(layout_type_1): 106 extra_split_.setOrientation(Qt::Horizontal); 107 /* Fall Through */ 108 case(layout_type_5): 109 master_split_.setOrientation(Qt::Vertical); 110 break; 111 112 case(layout_type_4): 113 case(layout_type_3): 114 extra_split_.setOrientation(Qt::Vertical); 115 /* Fall Through */ 116 case(layout_type_6): 117 master_split_.setOrientation(Qt::Horizontal); 118 break; 119 120 default: 121 ws_assert_not_reached(); 122 } 123 124 switch(prefs.gui_layout_type) { 125 case(layout_type_5): 126 case(layout_type_6): 127 parents[0] = &master_split_; 128 parents[1] = &master_split_; 129 parents[2] = &master_split_; 130 break; 131 case(layout_type_2): 132 case(layout_type_4): 133 parents[0] = &master_split_; 134 parents[1] = &extra_split_; 135 parents[2] = &extra_split_; 136 break; 137 case(layout_type_1): 138 case(layout_type_3): 139 parents[0] = &extra_split_; 140 parents[1] = &extra_split_; 141 parents[2] = &master_split_; 142 break; 143 default: 144 ws_assert_not_reached(); 145 } 146 147 if (parents[0] == &extra_split_) { 148 master_split_.addWidget(&extra_split_); 149 } 150 151 parents[0]->addWidget(getLayoutWidget(prefs.gui_layout_content_1)); 152 153 if (parents[2] == &extra_split_) { 154 master_split_.addWidget(&extra_split_); 155 } 156 157 parents[1]->addWidget(getLayoutWidget(prefs.gui_layout_content_2)); 158 parents[2]->addWidget(getLayoutWidget(prefs.gui_layout_content_3)); 159 160 const QList<QWidget *> ms_children = master_split_.findChildren<QWidget *>(); 161 162 extra_split_.setVisible(ms_children.contains(&extra_split_)); 163 packet_list_->setVisible(ms_children.contains(packet_list_) && recent.packet_list_show); 164 proto_tree_->setVisible(ms_children.contains(proto_tree_) && recent.tree_view_show); 165 byte_view_tab_->setVisible(ms_children.contains(byte_view_tab_) && recent.byte_view_show); 166 packet_diagram_->setVisible(ms_children.contains(packet_diagram_) && recent.packet_diagram_show); 167 168 // Show the packet list here to prevent pending resize events changing columns 169 // when the packet list is set as current widget for the first time. 170 packet_list_->show(); 171 172 packet_list_->thaw(true); 173 cur_layout_ = new_layout; 174 } 175 176 // The recent layout geometry should be applied after the layout has been 177 // applied AND at the following times: 178 // - At startup 179 // - When the profile changes applyRecentPaneGeometry()180void MainWindow::applyRecentPaneGeometry() 181 { 182 // XXX This shrinks slightly each time the application is run. For some 183 // reason the master_split_ geometry is two pixels shorter when 184 // saveWindowGeometry is invoked. 185 186 // This is also an awful lot of trouble to go through to reuse the GTK+ 187 // pane settings. We might want to add gui.geometry_main_master_sizes 188 // and gui.geometry_main_extra_sizes and save QSplitter::saveState in 189 // each. 190 191 // Force a geometry recalculation 192 QWidget *cur_w = main_ui_->mainStack->currentWidget(); 193 showCapture(); 194 QRect geom = main_ui_->mainStack->geometry(); 195 QList<int> master_sizes = master_split_.sizes(); 196 QList<int> extra_sizes = extra_split_.sizes(); 197 main_ui_->mainStack->setCurrentWidget(cur_w); 198 199 int master_last_size = master_split_.orientation() == Qt::Vertical ? geom.height() : geom.width(); 200 master_last_size -= master_split_.handleWidth() * (master_sizes.length() - 1); 201 202 int extra_last_size = extra_split_.orientation() == Qt::Vertical ? geom.height() : geom.width(); 203 extra_last_size -= extra_split_.handleWidth(); 204 205 if (recent.gui_geometry_main_upper_pane > 0) { 206 master_sizes[0] = recent.gui_geometry_main_upper_pane; 207 master_last_size -= recent.gui_geometry_main_upper_pane; 208 } else { 209 master_sizes[0] = master_last_size / master_sizes.length(); 210 master_last_size -= master_last_size / master_sizes.length(); 211 } 212 213 if (recent.gui_geometry_main_lower_pane > 0) { 214 if (master_sizes.length() > 2) { 215 master_sizes[1] = recent.gui_geometry_main_lower_pane; 216 master_last_size -= recent.gui_geometry_main_lower_pane; 217 } else if (extra_sizes.length() > 0) { 218 extra_sizes[0] = recent.gui_geometry_main_lower_pane; 219 extra_last_size -= recent.gui_geometry_main_lower_pane; 220 extra_sizes.last() = extra_last_size; 221 } 222 } else { 223 if (master_sizes.length() > 2) { 224 master_sizes[1] = master_last_size / 2; 225 master_last_size -= master_last_size / 2; 226 } else if (extra_sizes.length() > 0) { 227 extra_sizes[0] = extra_last_size / 2; 228 extra_last_size -= extra_last_size / 2; 229 extra_sizes.last() = extra_last_size; 230 } 231 } 232 233 master_sizes.last() = master_last_size; 234 235 master_split_.setSizes(master_sizes); 236 extra_split_.setSizes(extra_sizes); 237 } 238