Changeset 66552 in vbox
- Timestamp:
- Apr 13, 2017 10:08:10 AM (7 years ago)
- Location:
- trunk/src/VBox/Frontends/VirtualBox/src
- Files:
-
- 4 edited
-
globals/UIMessageCenter.cpp (modified) (2 diffs)
-
globals/UIMessageCenter.h (modified) (1 diff)
-
settings/machine/UIMachineSettingsUSB.cpp (modified) (2 diffs)
-
settings/machine/UIMachineSettingsUSB.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp
r66549 r66552 62 62 # include "CSharedFolder.h" 63 63 # include "CStorageController.h" 64 # include "CUSBController.h" 65 # include "CUSBDeviceFilters.h" 66 # include "CUSBDeviceFilter.h" 64 67 # include "CConsole.h" 65 68 # include "CMachine.h" … … 1316 1319 tr("Cannot save system settings."), 1317 1320 formatErrorInfo(comMachine)); 1321 } 1322 1323 void UIMessageCenter::cannotSaveUSBSettings(const CMachine &comMachine, QWidget *pParent /* = 0 */) 1324 { 1325 error(pParent, MessageType_Error, 1326 tr("Cannot save USB settings."), 1327 formatErrorInfo(comMachine)); 1328 } 1329 1330 void UIMessageCenter::cannotSaveUSBControllerSettings(const CUSBController &comController, QWidget *pParent /* = 0 */) 1331 { 1332 error(pParent, MessageType_Error, 1333 tr("Cannot save USB controller settings."), 1334 formatErrorInfo(comController)); 1335 } 1336 1337 void UIMessageCenter::cannotSaveUSBDeviceFiltersSettings(const CUSBDeviceFilters &comFilters, QWidget *pParent /* = 0 */) 1338 { 1339 error(pParent, MessageType_Error, 1340 tr("Cannot save USB device filters settings."), 1341 formatErrorInfo(comFilters)); 1342 } 1343 1344 void UIMessageCenter::cannotSaveUSBDeviceFilterSettings(const CUSBDeviceFilter &comFilter, QWidget *pParent /* = 0 */) 1345 { 1346 error(pParent, MessageType_Error, 1347 tr("Cannot save USB device filter settings."), 1348 formatErrorInfo(comFilter)); 1318 1349 } 1319 1350 -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.h
r66549 r66552 262 262 void cannotSaveStorageControllerSettings(const CStorageController &comController, QWidget *pParent = 0); 263 263 void cannotSaveSystemSettings(const CMachine &comMachine, QWidget *pParent = 0); 264 void cannotSaveUSBSettings(const CMachine &comMachine, QWidget *pParent = 0); 265 void cannotSaveUSBControllerSettings(const CUSBController &comController, QWidget *pParent = 0); 266 void cannotSaveUSBDeviceFiltersSettings(const CUSBDeviceFilters &comFilters, QWidget *pParent = 0); 267 void cannotSaveUSBDeviceFilterSettings(const CUSBDeviceFilter &comFilter, QWidget *pParent = 0); 264 268 void cannotAttachDevice(const CMachine &machine, UIMediumType type, const QString &strLocation, const StorageSlot &storageSlot, QWidget *pParent = 0); 265 269 bool warnAboutIncorrectPort(QWidget *pParent = 0) const; -
trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.cpp
r66460 r66552 485 485 UISettingsPageMachine::fetchData(data); 486 486 487 /* Make sure machine is in valid mode & USB data was changed: */ 488 if (isMachineInValidMode() && m_pCache->wasChanged()) 489 { 490 /* Get old USB data from the cache: */ 491 const UIDataSettingsMachineUSB &oldUsbData = m_pCache->base(); 492 /* Get new USB data from the cache: */ 493 const UIDataSettingsMachineUSB &newUsbData = m_pCache->data(); 494 495 /* Store USB data: */ 496 if (isMachineOffline() && newUsbData != oldUsbData) 497 { 498 /* Removing USB controllers: */ 499 if (!newUsbData.m_fUSBEnabled) 500 { 501 /* Get current USB controllers: */ 502 const CUSBControllerVector &controllers = m_machine.GetUSBControllers(); 503 for (int iControllerIndex = 0; iControllerIndex < controllers.size(); ++iControllerIndex) 504 { 505 /* Get current USB controller: */ 506 const CUSBController &controller = controllers.at(iControllerIndex); 507 /* Remove current USB controller: */ 508 m_machine.RemoveUSBController(controller.GetName()); 509 } 510 } 511 512 else 513 514 /* Creating/replacing USB controller: */ 515 if (newUsbData.m_fUSBEnabled) 516 { 517 /* Get each controller count: */ 518 const ULONG cOhciCtls = m_machine.GetUSBControllerCountByType(KUSBControllerType_OHCI); 519 const ULONG cEhciCtls = m_machine.GetUSBControllerCountByType(KUSBControllerType_EHCI); 520 const ULONG cXhciCtls = m_machine.GetUSBControllerCountByType(KUSBControllerType_XHCI); 521 522 /* For requested controller type: */ 523 switch (newUsbData.m_USBControllerType) 524 { 525 case KUSBControllerType_OHCI: 526 { 527 /* Remove excessive controllers: */ 528 if (cXhciCtls || cEhciCtls) 529 { 530 /* Get current USB controllers: */ 531 const CUSBControllerVector &controllers = m_machine.GetUSBControllers(); 532 for (int iControllerIndex = 0; iControllerIndex < controllers.size(); ++iControllerIndex) 533 { 534 /* Get current USB controller: */ 535 const CUSBController &controller = controllers.at(iControllerIndex); 536 const KUSBControllerType enmType = controller.GetType(); 537 /* Remove required USB controller: */ 538 if ( enmType == KUSBControllerType_XHCI 539 || enmType == KUSBControllerType_EHCI) 540 m_machine.RemoveUSBController(controller.GetName()); 541 } 542 } 543 544 /* Add required controller: */ 545 if (!cOhciCtls) 546 m_machine.AddUSBController("OHCI", KUSBControllerType_OHCI); 547 548 break; 549 } 550 case KUSBControllerType_EHCI: 551 { 552 /* Remove excessive controllers: */ 553 if (cXhciCtls) 554 { 555 /* Get current USB controllers: */ 556 const CUSBControllerVector &controllers = m_machine.GetUSBControllers(); 557 for (int iControllerIndex = 0; iControllerIndex < controllers.size(); ++iControllerIndex) 558 { 559 /* Get current USB controller: */ 560 const CUSBController &controller = controllers.at(iControllerIndex); 561 const KUSBControllerType enmType = controller.GetType(); 562 /* Remove required USB controller: */ 563 if (enmType == KUSBControllerType_XHCI) 564 m_machine.RemoveUSBController(controller.GetName()); 565 } 566 } 567 568 /* Add required controllers: */ 569 if (!cOhciCtls) 570 m_machine.AddUSBController("OHCI", KUSBControllerType_OHCI); 571 if (!cEhciCtls) 572 m_machine.AddUSBController("EHCI", KUSBControllerType_EHCI); 573 574 break; 575 } 576 case KUSBControllerType_XHCI: 577 { 578 /* Remove excessive controllers: */ 579 if (cEhciCtls || cOhciCtls) 580 { 581 /* Get current USB controllers: */ 582 const CUSBControllerVector &controllers = m_machine.GetUSBControllers(); 583 for (int iControllerIndex = 0; iControllerIndex < controllers.size(); ++iControllerIndex) 584 { 585 /* Get current USB controller: */ 586 const CUSBController &controller = controllers.at(iControllerIndex); 587 const KUSBControllerType enmType = controller.GetType(); 588 /* Remove required USB controller: */ 589 if ( enmType == KUSBControllerType_EHCI 590 || enmType == KUSBControllerType_OHCI) 591 m_machine.RemoveUSBController(controller.GetName()); 592 } 593 } 594 595 /* Add required controller: */ 596 if (!cXhciCtls) 597 m_machine.AddUSBController("xHCI", KUSBControllerType_XHCI); 598 599 break; 600 } 601 default: 602 break; 603 } 604 } 605 } 606 607 /* Store USB filters data: */ 608 CUSBDeviceFilters filtersObject = m_machine.GetUSBDeviceFilters(); 609 /* Check if controller is valid: */ 610 if (!filtersObject.isNull()) 611 { 612 /* For each USB filter data set: */ 613 int iOperationPosition = 0; 614 for (int iFilterIndex = 0; iFilterIndex < m_pCache->childCount(); ++iFilterIndex) 615 { 616 /* Check if USB filter data was changed: */ 617 const UISettingsCacheMachineUSBFilter &filterCache = m_pCache->child(iFilterIndex); 618 if (filterCache.wasChanged()) 619 { 620 /* If filter was removed or updated: */ 621 if (filterCache.wasRemoved() || filterCache.wasUpdated()) 622 { 623 /* Remove current USB filter: */ 624 filtersObject.RemoveDeviceFilter(iOperationPosition); 625 if (filtersObject.isOk() && filterCache.wasRemoved()) 626 --iOperationPosition; 627 } 628 629 /* If filter was created or updated: */ 630 if (filterCache.wasCreated() || filterCache.wasUpdated()) 631 { 632 /* Get new filter data from the cache: */ 633 const UIDataSettingsMachineUSBFilter &newFilterData = filterCache.data(); 634 635 /* Store USB filter data: */ 636 CUSBDeviceFilter filter = filtersObject.CreateDeviceFilter(newFilterData.m_strName); 637 if (!filter.isNull()) 638 { 639 /* Set whether filter is active: */ 640 filter.SetActive(newFilterData.m_fActive); 641 /* Set filter Vendor ID: */ 642 filter.SetVendorId(newFilterData.m_strVendorId); 643 /* Set filter Product ID: */ 644 filter.SetProductId(newFilterData.m_strProductId); 645 /* Set filter revision: */ 646 filter.SetRevision(newFilterData.m_strRevision); 647 /* Set filter manufacturer: */ 648 filter.SetManufacturer(newFilterData.m_strManufacturer); 649 /* Set filter product: */ 650 filter.SetProduct(newFilterData.m_strProduct); 651 /* Set filter serial number: */ 652 filter.SetSerialNumber(newFilterData.m_strSerialNumber); 653 /* Set filter port: */ 654 filter.SetPort(newFilterData.m_strPort); 655 /* Set filter remote mode: */ 656 filter.SetRemote(newFilterData.m_strRemote); 657 658 /* Insert filter onto corresponding position: */ 659 filtersObject.InsertDeviceFilter(iOperationPosition, filter); 660 } 661 } 662 } 663 /* Advance operation position: */ 664 ++iOperationPosition; 665 } 666 } 667 } 487 /* Update USB data and failing state: */ 488 setFailed(!saveUSBData()); 668 489 669 490 /* Upload machine to data: */ … … 1161 982 } 1162 983 984 bool UIMachineSettingsUSB::saveUSBData() 985 { 986 /* Prepare result: */ 987 bool fSuccess = true; 988 /* Save USB settings from the cache: */ 989 if (fSuccess && isMachineInValidMode() && m_pCache->wasChanged()) 990 { 991 /* Get new USB data from the cache: */ 992 const UIDataSettingsMachineUSB &newUsbData = m_pCache->data(); 993 994 /* Save USB data: */ 995 if (fSuccess && isMachineOffline()) 996 { 997 /* Remove USB controllers: */ 998 if (!newUsbData.m_fUSBEnabled) 999 fSuccess = removeUSBControllers(); 1000 1001 else 1002 1003 /* Create/update USB controllers: */ 1004 if (newUsbData.m_fUSBEnabled) 1005 fSuccess = createUSBControllers(newUsbData.m_USBControllerType); 1006 } 1007 1008 /* Save USB filters data: */ 1009 if (fSuccess) 1010 { 1011 /* Make sure filters object really exists: */ 1012 CUSBDeviceFilters comFiltersObject = m_machine.GetUSBDeviceFilters(); 1013 fSuccess = m_machine.isOk() && comFiltersObject.isNotNull(); 1014 /* Show error message if necessary: */ 1015 if (!fSuccess) 1016 msgCenter().cannotSaveUSBSettings(m_machine, this); 1017 1018 /* For each filter data set: */ 1019 int iOperationPosition = 0; 1020 for (int iFilterIndex = 0; fSuccess && iFilterIndex < m_pCache->childCount(); ++iFilterIndex) 1021 { 1022 /* Check if USB filter data was changed: */ 1023 const UISettingsCacheMachineUSBFilter &filterCache = m_pCache->child(iFilterIndex); 1024 if (filterCache.wasChanged()) 1025 { 1026 /* Remove filter marked for 'remove' or 'update': */ 1027 if (filterCache.wasRemoved() || filterCache.wasUpdated()) 1028 { 1029 fSuccess = removeUSBFilter(comFiltersObject, iOperationPosition); 1030 if (fSuccess && filterCache.wasRemoved()) 1031 --iOperationPosition; 1032 } 1033 1034 /* Create filter marked for 'create' or 'update': */ 1035 if (filterCache.wasCreated() || filterCache.wasUpdated()) 1036 fSuccess = createUSBFilter(comFiltersObject, iOperationPosition, filterCache.data()); 1037 } 1038 /* Advance operation position: */ 1039 ++iOperationPosition; 1040 } 1041 } 1042 } 1043 /* Return result: */ 1044 return fSuccess; 1045 } 1046 1047 bool UIMachineSettingsUSB::removeUSBControllers(const QSet<KUSBControllerType> &types /* = QSet<KUSBControllerType>() */) 1048 { 1049 /* Prepare result: */ 1050 bool fSuccess = true; 1051 /* Remove controllers: */ 1052 if (fSuccess && isMachineOffline()) 1053 { 1054 /* Get controllers for further activities: */ 1055 const CUSBControllerVector &controllers = m_machine.GetUSBControllers(); 1056 fSuccess = m_machine.isOk(); 1057 /* Show error message if necessary: */ 1058 if (!fSuccess) 1059 msgCenter().cannotSaveUSBSettings(m_machine, this); 1060 1061 /* For each controller: */ 1062 for (int iControllerIndex = 0; fSuccess && iControllerIndex < controllers.size(); ++iControllerIndex) 1063 { 1064 /* Get current controller: */ 1065 const CUSBController &comController = controllers.at(iControllerIndex); 1066 1067 /* Get controller type for further activities: */ 1068 KUSBControllerType enmType = KUSBControllerType_Null; 1069 if (fSuccess) 1070 { 1071 enmType = comController.GetType(); 1072 fSuccess = comController.isOk(); 1073 } 1074 /* Get controller name for further activities: */ 1075 QString strName; 1076 if (fSuccess) 1077 { 1078 strName = comController.GetName(); 1079 fSuccess = comController.isOk(); 1080 } 1081 /* Show error message if necessary: */ 1082 if (!fSuccess) 1083 msgCenter().cannotSaveUSBControllerSettings(comController, this); 1084 1085 /* Pass only if requested types were not defined or contains the one we found: */ 1086 if (!types.isEmpty() && !types.contains(enmType)) 1087 continue; 1088 1089 /* Remove controller: */ 1090 if (fSuccess) 1091 { 1092 m_machine.RemoveUSBController(comController.GetName()); 1093 fSuccess = m_machine.isOk(); 1094 } 1095 /* Show error message if necessary: */ 1096 if (!fSuccess) 1097 msgCenter().cannotSaveUSBSettings(m_machine, this); 1098 } 1099 } 1100 /* Return result: */ 1101 return fSuccess; 1102 } 1103 1104 bool UIMachineSettingsUSB::createUSBControllers(KUSBControllerType enmType) 1105 { 1106 /* Prepare result: */ 1107 bool fSuccess = true; 1108 /* Add controllers: */ 1109 if (fSuccess && isMachineOffline()) 1110 { 1111 /* Get each controller count for further activities: */ 1112 ULONG cOhciCtls = 0; 1113 if (fSuccess) 1114 { 1115 cOhciCtls = m_machine.GetUSBControllerCountByType(KUSBControllerType_OHCI); 1116 fSuccess = m_machine.isOk(); 1117 } 1118 ULONG cEhciCtls = 0; 1119 if (fSuccess) 1120 { 1121 cEhciCtls = m_machine.GetUSBControllerCountByType(KUSBControllerType_EHCI); 1122 fSuccess = m_machine.isOk(); 1123 } 1124 ULONG cXhciCtls = 0; 1125 if (fSuccess) 1126 { 1127 cXhciCtls = m_machine.GetUSBControllerCountByType(KUSBControllerType_XHCI); 1128 fSuccess = m_machine.isOk(); 1129 } 1130 /* Show error message if necessary: */ 1131 if (!fSuccess) 1132 msgCenter().cannotSaveUSBSettings(m_machine, this); 1133 1134 /* For requested controller type: */ 1135 switch (enmType) 1136 { 1137 case KUSBControllerType_OHCI: 1138 { 1139 /* Remove excessive controllers: */ 1140 if (cXhciCtls || cEhciCtls) 1141 fSuccess = removeUSBControllers(QSet<KUSBControllerType>() 1142 << KUSBControllerType_XHCI 1143 << KUSBControllerType_EHCI); 1144 1145 /* Add required controller: */ 1146 if (fSuccess && !cOhciCtls) 1147 { 1148 m_machine.AddUSBController("OHCI", KUSBControllerType_OHCI); 1149 fSuccess = m_machine.isOk(); 1150 } 1151 /* Show error message if necessary: */ 1152 if (!fSuccess) 1153 msgCenter().cannotSaveUSBSettings(m_machine, this); 1154 1155 break; 1156 } 1157 case KUSBControllerType_EHCI: 1158 { 1159 /* Remove excessive controllers: */ 1160 if (cXhciCtls) 1161 fSuccess = removeUSBControllers(QSet<KUSBControllerType>() 1162 << KUSBControllerType_XHCI); 1163 1164 /* Add required controllers: */ 1165 if (fSuccess && !cOhciCtls) 1166 { 1167 m_machine.AddUSBController("OHCI", KUSBControllerType_OHCI); 1168 fSuccess = m_machine.isOk(); 1169 } 1170 if (fSuccess && !cEhciCtls) 1171 { 1172 m_machine.AddUSBController("EHCI", KUSBControllerType_EHCI); 1173 fSuccess = m_machine.isOk(); 1174 } 1175 /* Show error message if necessary: */ 1176 if (!fSuccess) 1177 msgCenter().cannotSaveUSBSettings(m_machine, this); 1178 1179 break; 1180 } 1181 case KUSBControllerType_XHCI: 1182 { 1183 /* Remove excessive controllers: */ 1184 if (cEhciCtls || cOhciCtls) 1185 fSuccess = removeUSBControllers(QSet<KUSBControllerType>() 1186 << KUSBControllerType_EHCI 1187 << KUSBControllerType_OHCI); 1188 1189 /* Add required controller: */ 1190 if (fSuccess && !cXhciCtls) 1191 { 1192 m_machine.AddUSBController("xHCI", KUSBControllerType_XHCI); 1193 fSuccess = m_machine.isOk(); 1194 } 1195 /* Show error message if necessary: */ 1196 if (!fSuccess) 1197 msgCenter().cannotSaveUSBSettings(m_machine, this); 1198 1199 break; 1200 } 1201 default: 1202 break; 1203 } 1204 } 1205 /* Return result: */ 1206 return fSuccess; 1207 } 1208 1209 bool UIMachineSettingsUSB::removeUSBFilter(CUSBDeviceFilters &comFiltersObject, int iPosition) 1210 { 1211 /* Prepare result: */ 1212 bool fSuccess = true; 1213 /* Remove filter: */ 1214 if (fSuccess) 1215 { 1216 /* Remove filter: */ 1217 comFiltersObject.RemoveDeviceFilter(iPosition); 1218 fSuccess = comFiltersObject.isOk(); 1219 /* Show error message if necessary: */ 1220 if (!fSuccess) 1221 msgCenter().cannotSaveUSBDeviceFiltersSettings(comFiltersObject, this); 1222 } 1223 /* Return result: */ 1224 return fSuccess; 1225 } 1226 1227 bool UIMachineSettingsUSB::createUSBFilter(CUSBDeviceFilters &comFiltersObject, int iPosition, const UIDataSettingsMachineUSBFilter &filterData) 1228 { 1229 /* Prepare result: */ 1230 bool fSuccess = true; 1231 /* Add filter: */ 1232 if (fSuccess) 1233 { 1234 /* Create filter: */ 1235 CUSBDeviceFilter comFilter = comFiltersObject.CreateDeviceFilter(filterData.m_strName); 1236 fSuccess = comFiltersObject.isOk() && comFilter.isNotNull(); 1237 /* Show error message if necessary: */ 1238 if (!fSuccess) 1239 msgCenter().cannotSaveUSBDeviceFiltersSettings(comFiltersObject, this); 1240 1241 /* Save whether filter is active: */ 1242 if (fSuccess) 1243 { 1244 comFilter.SetActive(filterData.m_fActive); 1245 fSuccess = comFilter.isOk(); 1246 } 1247 /* Save filter Vendor ID: */ 1248 if (fSuccess) 1249 { 1250 comFilter.SetVendorId(filterData.m_strVendorId); 1251 fSuccess = comFilter.isOk(); 1252 } 1253 /* Save filter Product ID: */ 1254 if (fSuccess) 1255 { 1256 comFilter.SetProductId(filterData.m_strProductId); 1257 fSuccess = comFilter.isOk(); 1258 } 1259 /* Save filter revision: */ 1260 if (fSuccess) 1261 { 1262 comFilter.SetRevision(filterData.m_strRevision); 1263 fSuccess = comFilter.isOk(); 1264 } 1265 /* Save filter manufacturer: */ 1266 if (fSuccess) 1267 { 1268 comFilter.SetManufacturer(filterData.m_strManufacturer); 1269 fSuccess = comFilter.isOk(); 1270 } 1271 /* Save filter product: */ 1272 if (fSuccess) 1273 { 1274 comFilter.SetProduct(filterData.m_strProduct); 1275 fSuccess = comFilter.isOk(); 1276 } 1277 /* Save filter serial number: */ 1278 if (fSuccess) 1279 { 1280 comFilter.SetSerialNumber(filterData.m_strSerialNumber); 1281 fSuccess = comFilter.isOk(); 1282 } 1283 /* Save filter port: */ 1284 if (fSuccess) 1285 { 1286 comFilter.SetPort(filterData.m_strPort); 1287 fSuccess = comFilter.isOk(); 1288 } 1289 /* Save filter remote mode: */ 1290 if (fSuccess) 1291 { 1292 comFilter.SetRemote(filterData.m_strRemote); 1293 fSuccess = comFilter.isOk(); 1294 } 1295 /* Show error message if necessary: */ 1296 if (!fSuccess) 1297 msgCenter().cannotSaveUSBDeviceFilterSettings(comFilter, this); 1298 1299 /* Insert filter onto corresponding position: */ 1300 if (fSuccess) 1301 { 1302 comFiltersObject.InsertDeviceFilter(iPosition, comFilter); 1303 fSuccess = comFiltersObject.isOk(); 1304 } 1305 /* Show error message if necessary: */ 1306 if (!fSuccess) 1307 msgCenter().cannotSaveUSBDeviceFiltersSettings(comFiltersObject, this); 1308 } 1309 /* Return result: */ 1310 return fSuccess; 1311 } 1312 1163 1313 #include "UIMachineSettingsUSB.moc" 1164 1314 -
trunk/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.h
r66455 r66552 125 125 void addUSBFilterItem(const UIDataSettingsMachineUSBFilter &filterData, bool fChoose); 126 126 127 /** Returns the multi-line description of the given USB filter. */ 128 static QString toolTipFor(const UIDataSettingsMachineUSBFilter &data); 127 /** Saves existing USB data from the cache. */ 128 bool saveUSBData(); 129 /** Removes USB controllers of passed @a types. */ 130 bool removeUSBControllers(const QSet<KUSBControllerType> &types = QSet<KUSBControllerType>()); 131 /** Creates USB controllers of passed @a enmType. */ 132 bool createUSBControllers(KUSBControllerType enmType); 133 /** Removes USB filter at passed @a iPosition of the @a filtersObject. */ 134 bool removeUSBFilter(CUSBDeviceFilters &comFiltersObject, int iPosition); 135 /** Creates USB filter at passed @a iPosition of the @a filtersObject using the @a filterData. */ 136 bool createUSBFilter(CUSBDeviceFilters &comFiltersObject, int iPosition, const UIDataSettingsMachineUSBFilter &filterData); 129 137 130 138 /** Holds the toolbar instance. */
Note:
See TracChangeset
for help on using the changeset viewer.

