1 /* 2 Copyright (C) 2010-2014 Kristian Duske 3 4 This file is part of TrenchBroom. 5 6 TrenchBroom is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 TrenchBroom is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "KeyboardShortcutGridTable.h" 21 22 #include "View/ActionManager.h" 23 #include "View/KeyboardGridCellEditor.h" 24 #include "View/KeyboardShortcutEntry.h" 25 #include "View/Menu.h" 26 27 namespace TrenchBroom { 28 namespace View { KeyboardShortcutGridTable()29 KeyboardShortcutGridTable::KeyboardShortcutGridTable() : 30 m_cellEditor(new KeyboardGridCellEditor()) { 31 m_cellEditor->IncRef(); 32 } 33 ~KeyboardShortcutGridTable()34 KeyboardShortcutGridTable::~KeyboardShortcutGridTable() { 35 m_cellEditor->DecRef(); 36 } 37 GetNumberRows()38 int KeyboardShortcutGridTable::GetNumberRows() { 39 return static_cast<int>(m_entries.size()); 40 } 41 GetNumberCols()42 int KeyboardShortcutGridTable::GetNumberCols() { 43 return 3; 44 } 45 GetValue(int row,int col)46 wxString KeyboardShortcutGridTable::GetValue(int row, int col) { 47 assert(row >= 0 && row < GetNumberRows()); 48 assert(col >= 0 && col < GetNumberCols()); 49 50 size_t rowIndex = static_cast<size_t>(row); 51 52 switch (col) { 53 case 0: 54 return m_entries[rowIndex]->shortcutDescription(); 55 case 1: 56 return m_entries[rowIndex]->actionContextDescription(); 57 case 2: 58 return m_entries[rowIndex]->actionDescription(); 59 default: 60 assert(false); 61 break; 62 } 63 64 return ""; 65 } 66 SetValue(int row,int col,const wxString & value)67 void KeyboardShortcutGridTable::SetValue(int row, int col, const wxString& value) { 68 assert(row >= 0 && row < GetNumberRows()); 69 assert(col == 0); 70 71 int key, modifier1, modifier2, modifier3; 72 const bool success = KeyboardShortcut::parseShortcut(value, key, modifier1, modifier2, modifier3); 73 assert(success); 74 unused(success); 75 76 const size_t rowIndex = static_cast<size_t>(row); 77 m_entries[rowIndex]->updateShortcut(KeyboardShortcut(key, modifier1, modifier2, modifier3)); 78 79 if (markConflicts(m_entries)) 80 notifyRowsUpdated(m_entries.size()); 81 else 82 notifyRowsUpdated(rowIndex, 1); 83 } 84 Clear()85 void KeyboardShortcutGridTable::Clear() { 86 assert(false); 87 } 88 InsertRows(size_t pos,size_t numRows)89 bool KeyboardShortcutGridTable::InsertRows(size_t pos, size_t numRows) { 90 assert(false); 91 return false; 92 } 93 AppendRows(size_t numRows)94 bool KeyboardShortcutGridTable::AppendRows(size_t numRows) { 95 assert(false); 96 return false; 97 } 98 DeleteRows(size_t pos,size_t numRows)99 bool KeyboardShortcutGridTable::DeleteRows(size_t pos, size_t numRows) { 100 assert(false); 101 return false; 102 } 103 GetColLabelValue(int col)104 wxString KeyboardShortcutGridTable::GetColLabelValue(int col) { 105 assert(col >= 0 && col < GetNumberCols()); 106 switch (col) { 107 case 0: 108 return "Shortcut"; 109 case 1: 110 return "Context"; 111 case 2: 112 return "Description"; 113 default: 114 assert(false); 115 break; 116 } 117 118 return ""; 119 } 120 GetAttr(int row,int col,wxGridCellAttr::wxAttrKind kind)121 wxGridCellAttr* KeyboardShortcutGridTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) { 122 wxGridCellAttr* attr = wxGridTableBase::GetAttr(row, col, kind); 123 if (row >= 0 && row < GetNumberRows()) { 124 const KeyboardShortcutEntry* entry = m_entries[static_cast<size_t>(row)]; 125 if (entry->hasConflicts()) { 126 if (attr == NULL) 127 attr = new wxGridCellAttr(); 128 attr->SetTextColour(*wxRED); 129 } 130 if (col == 0) { 131 if (attr == NULL) 132 attr = new wxGridCellAttr(); 133 if (entry->modifiable()) { 134 attr->SetEditor(m_cellEditor); 135 m_cellEditor->IncRef(); 136 } else { 137 attr->SetReadOnly(true); 138 attr->SetTextColour(*wxLIGHT_GREY); 139 } 140 } else { 141 if (attr == NULL) 142 attr = new wxGridCellAttr(); 143 attr->SetReadOnly(true); 144 } 145 } 146 return attr; 147 } 148 hasDuplicates() const149 bool KeyboardShortcutGridTable::hasDuplicates() const { 150 for (size_t i = 0; i < m_entries.size(); i++) 151 if (m_entries[i]->hasConflicts()) 152 return true; 153 return false; 154 } 155 update()156 bool KeyboardShortcutGridTable::update() { 157 EntryList newEntries; 158 159 ActionManager& actionManager = ActionManager::instance(); 160 actionManager.getShortcutEntries(newEntries); 161 162 const bool hasConflicts = markConflicts(newEntries); 163 164 size_t oldSize = m_entries.size(); 165 m_entries = newEntries; 166 167 notifyRowsUpdated(0, oldSize); 168 if (oldSize < m_entries.size()) 169 notifyRowsAppended(m_entries.size() - oldSize); 170 else if (oldSize > m_entries.size()) 171 notifyRowsDeleted(oldSize, oldSize - m_entries.size()); 172 173 return hasConflicts; 174 } 175 notifyRowsUpdated(size_t pos,size_t numRows)176 void KeyboardShortcutGridTable::notifyRowsUpdated(size_t pos, size_t numRows) { 177 if (GetView() != NULL) { 178 wxGridTableMessage message(this, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES, 179 static_cast<int>(pos), 180 static_cast<int>(numRows)); 181 GetView()->ProcessTableMessage(message); 182 } 183 } 184 notifyRowsInserted(size_t pos,size_t numRows)185 void KeyboardShortcutGridTable::notifyRowsInserted(size_t pos, size_t numRows) { 186 if (GetView() != NULL) { 187 wxGridTableMessage message(this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, 188 static_cast<int>(pos), 189 static_cast<int>(numRows)); 190 GetView()->ProcessTableMessage(message); 191 } 192 } 193 notifyRowsAppended(size_t numRows)194 void KeyboardShortcutGridTable::notifyRowsAppended(size_t numRows) { 195 if (GetView() != NULL) { 196 wxGridTableMessage message(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 197 static_cast<int>(numRows)); 198 GetView()->ProcessTableMessage(message); 199 } 200 } 201 notifyRowsDeleted(size_t pos,size_t numRows)202 void KeyboardShortcutGridTable::notifyRowsDeleted(size_t pos, size_t numRows) { 203 if (GetView() != NULL) { 204 wxGridTableMessage message(this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 205 static_cast<int>(pos), 206 static_cast<int>(numRows)); 207 GetView()->ProcessTableMessage(message); 208 } 209 } 210 markConflicts(EntryList & entries)211 bool KeyboardShortcutGridTable::markConflicts(EntryList& entries) { 212 for (size_t i = 0; i < entries.size(); i++) 213 entries[i]->resetConflicts(); 214 215 bool hasConflicts = false; 216 for (size_t i = 0; i < entries.size(); i++) { 217 KeyboardShortcutEntry* first = entries[i]; 218 for (size_t j = i + 1; j < entries.size(); j++) { 219 KeyboardShortcutEntry* second = entries[j]; 220 if (first->updateConflicts(second)) { 221 second->updateConflicts(first); 222 hasConflicts = true; 223 } 224 } 225 } 226 return hasConflicts; 227 } 228 } 229 } 230