Changeset 92790 in vbox for trunk/src/VBox
- Timestamp:
- Dec 7, 2021 6:18:45 PM (3 years ago)
- Location:
- trunk/src/VBox/Frontends/VirtualBox/src/guestctrl
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/guestctrl/UIFileManager.cpp
r92787 r92790 46 46 #include "CGuestFsObjInfo.h" 47 47 #include "CGuestSession.h" 48 #include "CGuestSessionStateChangedEvent.h"49 48 50 49 … … 129 128 , m_pLogPanel(0) 130 129 , m_pOperationsPanel(0) 130 , m_fCommitDataSignalReceived(false) 131 131 { 132 132 loadOptions(); … … 307 307 this, &UIFileManager::sltHandleOptionsUpdated); 308 308 } 309 connect(&uiCommon(), &UICommon::sigAskToCommitData, 310 this, &UIFileManager::sltCommitDataSignalReceived); 309 311 } 310 312 … … 415 417 } 416 418 419 void UIFileManager::sltCommitDataSignalReceived() 420 { 421 m_fCommitDataSignalReceived = true; 422 } 423 417 424 void UIFileManager::copyToHost() 418 425 { … … 486 493 void UIFileManager::saveOptions() 487 494 { 495 if (m_fCommitDataSignalReceived) 496 return; 488 497 /* Save the options: */ 489 498 UIFileManagerOptions *pOptions = UIFileManagerOptions::instance(); … … 596 605 void UIFileManager::savePanelVisibility() 597 606 { 607 if (m_fCommitDataSignalReceived) 608 return; 598 609 /* Save a list of currently visible panels: */ 599 610 QStringList strNameList; … … 664 675 if (comMachine.isNull()) 665 676 continue; 666 m_pGuestTablesContainer->addTab(new UIFileManagerGuestTable(m_pActionPool, comMachine, m_pGuestTablesContainer), comMachine.GetName()); 667 // if (m_pGuestFileTable) 668 // { 669 // connect(m_pGuestFileTable, &UIFileManagerGuestTable::sigLogOutput, 670 // this, &UIFileManager::sltReceieveLogOutput); 677 UIFileManagerGuestTable *pGuestFileTable = new UIFileManagerGuestTable(m_pActionPool, comMachine, m_pGuestTablesContainer); 678 m_pGuestTablesContainer->addTab(pGuestFileTable, comMachine.GetName()); 679 if (pGuestFileTable) 680 { 681 connect(pGuestFileTable, &UIFileManagerGuestTable::sigLogOutput, 682 this, &UIFileManager::sltReceieveLogOutput); 671 683 // connect(m_pGuestFileTable, &UIFileManagerGuestTable::sigNewFileOperation, 672 684 // this, &UIFileManager::sltReceieveNewFileOperation); 673 685 // connect(m_pGuestFileTable, &UIFileManagerGuestTable::sigDeleteConfirmationOptionChanged, 674 686 // this, &UIFileManager::sltHandleOptionsUpdated); 675 //}687 } 676 688 } 677 689 } -
trunk/src/VBox/Frontends/VirtualBox/src/guestctrl/UIFileManager.h
r92753 r92790 39 39 class QTextEdit; 40 40 class QVBoxLayout; 41 class CGuestSessionStateChangedEvent;42 41 class UIActionPool; 43 42 class UIDialogPanel; … … 114 113 void sltHandleOptionsUpdated(); 115 114 void sltHandleHidePanel(UIDialogPanel *pPanel); 115 void sltCommitDataSignalReceived(); 116 116 117 117 private: … … 151 151 void addTabs(const QVector<QUuid> &machineIdsToAdd); 152 152 153 154 153 QVBoxLayout *m_pMainLayout; 155 154 QSplitter *m_pVerticalSplitter; … … 170 169 UIFileManagerLogPanel *m_pLogPanel; 171 170 UIFileManagerOperationsPanel *m_pOperationsPanel; 172 bool m_fDialogBeingClosed;173 171 172 bool m_fCommitDataSignalReceived; 174 173 175 174 QVector<QUuid> m_machineIds; -
trunk/src/VBox/Frontends/VirtualBox/src/guestctrl/UIFileManagerGuestTable.cpp
r92788 r92790 162 162 prepareGuestSessionPanel(); 163 163 prepareActionConnections(); 164 setSessionDependentWidgetsEnabled(isSessionPossible());165 164 166 165 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineStateChange, … … 171 170 if (m_pActionPool && m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession)) 172 171 m_pActionPool->action(UIActionIndex_M_FileManager_T_GuestSession)->setChecked(true); 172 173 if (!m_comMachine.isNull() && m_comMachine.GetState() == KMachineState_Running) 174 openMachineSession(); 175 setSessionDependentWidgetsEnabled(isSessionPossible()); 176 173 177 retranslateUi(); 174 178 } … … 859 863 } 860 864 861 void UIFileManagerGuestTable::sltMachineStateChange(const QUuid &uMachineId, const KMachineState )865 void UIFileManagerGuestTable::sltMachineStateChange(const QUuid &uMachineId, const KMachineState enmMachineState) 862 866 { 863 867 if (uMachineId.isNull() || m_comMachine.isNull() || uMachineId != m_comMachine.GetId()) 864 868 return; 869 870 if (enmMachineState == KMachineState_Running) 871 openMachineSession(); 872 else 873 { 874 cleanAll(); 875 } 876 865 877 setSessionDependentWidgetsEnabled(isSessionPossible()); 866 878 retranslateUi(); 867 879 } 868 880 869 bool UIFileManagerGuestTable::openSession(const QString &strUserName, const QString &strPassword) 881 bool UIFileManagerGuestTable::closeMachineSession() 882 { 883 if (!m_comSession.isNull()) 884 m_comSession.UnlockMachine(); 885 886 if (!m_comGuest.isNull()) 887 m_comGuest.detach(); 888 889 if (!m_comSession.isNull()) 890 m_comSession.detach(); 891 if (!m_comConsole.isNull()) 892 m_comConsole.detach(); 893 894 return true; 895 } 896 897 bool UIFileManagerGuestTable::openMachineSession() 870 898 { 871 899 if (m_comMachine.isNull()) … … 881 909 } 882 910 883 CConsole comConsole = m_comSession.GetConsole(); 884 AssertReturn(!comConsole.isNull(), false); 885 m_comGuest = comConsole.GetGuest(); 886 AssertReturn(!m_comGuest.isNull(), false); 887 888 if (!isGuestAdditionsAvailable(m_comGuest)) 889 { 890 emit sigLogOutput("Could not find Guest Additions", m_strTableName, FileManagerLogType_Error); 891 postGuestSessionClosed(); 892 if (m_pGuestSessionPanel) 893 m_pGuestSessionPanel->markForError(true); 894 return false; 895 } 896 897 QVector<KVBoxEventType> eventTypes; 898 eventTypes << KVBoxEventType_OnGuestSessionRegistered; 899 900 prepareListener(m_pQtGuestListener, m_comGuestListener, 901 m_comGuest.GetEventSource(), eventTypes); 902 903 connect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionUnregistered, 904 this, &UIFileManagerGuestTable::sltGuestSessionUnregistered); 905 connect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionRegistered, 906 this, &UIFileManagerGuestTable::sltGuestSessionRegistered); 907 908 m_comGuestSession = m_comGuest.CreateSession(strUserName, strPassword, 909 QString() /* Domain */, "File Manager Session"); 910 911 if (!m_comGuestSession.isOk()) 912 { 913 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error); 914 cleanupGuestListener(); 915 return false; 916 } 917 918 eventTypes.clear(); 919 eventTypes << KVBoxEventType_OnGuestSessionStateChanged; 920 921 prepareListener(m_pQtSessionListener, m_comSessionListener, 922 m_comGuestSession.GetEventSource(), eventTypes); 923 924 qRegisterMetaType<CGuestSessionStateChangedEvent>(); 925 connect(m_pQtSessionListener->getWrapped(), &UIMainEventListener::sigGuestSessionStatedChanged, 926 this, &UIFileManagerGuestTable::sltGuestSessionStateChanged); 927 911 m_comConsole = m_comSession.GetConsole(); 912 if (m_comConsole.isNull()) 913 { 914 emit sigLogOutput("Machine console is invalid", m_strTableName, FileManagerLogType_Error); 915 return false; 916 } 917 918 m_comGuest = m_comConsole.GetGuest(); 919 if (m_comGuest.isNull()) 920 { 921 emit sigLogOutput("Guest reference is invalid", m_strTableName, FileManagerLogType_Error); 922 return false; 923 } 924 925 /* Prepare guest listener for guest session related events: */ 926 { 927 QVector<KVBoxEventType> eventTypes; 928 eventTypes << KVBoxEventType_OnGuestSessionRegistered; 929 prepareListener(m_pQtGuestListener, m_comGuestListener, m_comGuest.GetEventSource(), eventTypes); 930 connect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionUnregistered, 931 this, &UIFileManagerGuestTable::sltGuestSessionUnregistered); 932 connect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionRegistered, 933 this, &UIFileManagerGuestTable::sltGuestSessionRegistered); 934 } 935 936 /* Prepare console listener for guest additions state change events: */ 937 { 938 QVector<KVBoxEventType> eventTypes; 939 eventTypes << KVBoxEventType_OnAdditionsStateChanged; 940 prepareListener(m_pQtConsoleListener, m_comConsoleListener, m_comConsole.GetEventSource(), eventTypes); 941 connect(m_pQtConsoleListener->getWrapped(), &UIMainEventListener::sigAdditionsChange, 942 this, &UIFileManagerGuestTable::sltAdditionsStateChange); 943 } 944 emit sigLogOutput("Shared machine session opened", m_strTableName, FileManagerLogType_Info); 928 945 return true; 929 946 } 930 947 931 bool UIFileManagerGuestTable::isGuestAdditionsAvailable(CGuest &guest)932 {933 if (guest.isNull())934 return false;935 936 return guest.GetAdditionsStatus(guest.GetAdditionsRunLevel());937 }938 939 948 bool UIFileManagerGuestTable::isGuestAdditionsAvailable() 940 949 { 941 if (m_comMachine.isNull()) 942 return false; 943 CSession comSession = uiCommon().openSession(m_comMachine.GetId(), KLockType_Shared); 944 if (comSession.isNull()) 945 return false; 946 CConsole comConsole = comSession.GetConsole(); 947 if (comConsole.isNull()) 948 return false; 949 CGuest comGuest = comConsole.GetGuest(); 950 if (comGuest.isNull()) 951 return false; 952 return comGuest.GetAdditionsStatus(comGuest.GetAdditionsRunLevel()); 953 } 954 950 if (m_comGuest.isNull()) 951 return false; 952 return m_comGuest.GetAdditionsStatus(m_comGuest.GetAdditionsRunLevel()); 953 } 955 954 956 955 void UIFileManagerGuestTable::cleanupGuestListener() 957 956 { 958 disconnect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionUnregistered, 959 this, &UIFileManagerGuestTable::sltGuestSessionUnregistered); 960 disconnect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionRegistered, 961 this, &UIFileManagerGuestTable::sltGuestSessionRegistered); 962 cleanupListener(m_pQtGuestListener, m_comGuestListener, m_comGuest.GetEventSource()); 963 } 964 965 void UIFileManagerGuestTable::cleanupSessionListener() 966 { 967 disconnect(m_pQtSessionListener->getWrapped(), &UIMainEventListener::sigGuestSessionStatedChanged, 968 this, &UIFileManagerGuestTable::sltGuestSessionStateChanged); 969 cleanupListener(m_pQtSessionListener, m_comSessionListener, m_comGuest.GetEventSource()); 957 if (!m_pQtGuestListener.isNull()) 958 { 959 disconnect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionUnregistered, 960 this, &UIFileManagerGuestTable::sltGuestSessionUnregistered); 961 disconnect(m_pQtGuestListener->getWrapped(), &UIMainEventListener::sigGuestSessionRegistered, 962 this, &UIFileManagerGuestTable::sltGuestSessionRegistered); 963 if (!m_comGuest.isNull()) 964 cleanupListener(m_pQtGuestListener, m_comGuestListener, m_comGuest.GetEventSource()); 965 } 966 } 967 968 void UIFileManagerGuestTable::cleanupGuestSessionListener() 969 { 970 if (!m_pQtSessionListener.isNull()) 971 { 972 disconnect(m_pQtSessionListener->getWrapped(), &UIMainEventListener::sigGuestSessionStatedChanged, 973 this, &UIFileManagerGuestTable::sltGuestSessionStateChanged); 974 if (!m_comGuestSession.isNull()) 975 cleanupListener(m_pQtSessionListener, m_comSessionListener, m_comGuestSession.GetEventSource()); 976 } 977 } 978 979 void UIFileManagerGuestTable::cleanupConsoleListener() 980 { 981 if (!m_pQtConsoleListener.isNull()) 982 { 983 disconnect(m_pQtConsoleListener->getWrapped(), &UIMainEventListener::sigAdditionsChange, 984 this, &UIFileManagerGuestTable::sltAdditionsStateChange); 985 if (!m_comConsole.isNull()) 986 cleanupListener(m_pQtConsoleListener, m_comConsoleListener, m_comConsole.GetEventSource()); 987 } 970 988 } 971 989 … … 974 992 if (m_pGuestSessionPanel) 975 993 m_pGuestSessionPanel->switchSessionCloseMode(); 976 // if (m_pGuestFileTable)977 // m_pGuestFileTable->setEnabled(true);978 // if (m_pVerticalToolBar)979 // m_pVerticalToolBar->setEnabled(true);980 994 } 981 995 … … 984 998 if (m_pGuestSessionPanel) 985 999 m_pGuestSessionPanel->switchSessionCreateMode(); 986 // if (m_pGuestFileTable)987 // m_pGuestFileTable->setEnabled(false);988 // if (m_pVerticalToolBar)989 // m_pVerticalToolBar->setEnabled(false);990 1000 } 991 1001 … … 1006 1016 /* Register event sources in their listeners as well: */ 1007 1017 QtListener->getWrapped()->registerSource(comEventSource, comEventListener); 1018 } 1019 1020 void UIFileManagerGuestTable::cleanupListener(ComObjPtr<UIMainEventListenerImpl> &QtListener, 1021 CEventListener &comEventListener, 1022 CEventSource comEventSource) 1023 { 1024 if (!comEventSource.isOk()) 1025 return; 1026 /* Unregister everything: */ 1027 QtListener->getWrapped()->unregisterSources(); 1028 1029 /* Make sure VBoxSVC is available: */ 1030 if (!uiCommon().isVBoxSVCAvailable()) 1031 return; 1032 1033 /* Unregister event listener for CProgress event source: */ 1034 comEventSource.UnregisterListener(comEventListener); 1008 1035 } 1009 1036 … … 1048 1075 } 1049 1076 1050 void UIFileManagerGuestTable::cleanupListener(ComObjPtr<UIMainEventListenerImpl> &QtListener,1051 CEventListener &comEventListener,1052 CEventSource comEventSource)1053 {1054 if (!comEventSource.isOk())1055 return;1056 /* Unregister everything: */1057 QtListener->getWrapped()->unregisterSources();1058 1059 /* Make sure VBoxSVC is available: */1060 if (!uiCommon().isVBoxSVCAvailable())1061 return;1062 1063 /* Unregister event listener for CProgress event source: */1064 comEventSource.UnregisterListener(comEventListener);1065 }1066 1067 1077 void UIFileManagerGuestTable::sltCreateGuestSession(QString strUserName, QString strPassword) 1068 1078 { … … 1075 1085 } 1076 1086 if (m_pGuestSessionPanel) 1077 m_pGuestSessionPanel->markForError(!open Session(strUserName, strPassword));1087 m_pGuestSessionPanel->markForError(!openGuestSession(strUserName, strPassword)); 1078 1088 } 1079 1089 … … 1101 1111 void UIFileManagerGuestTable::sltHandleCloseSessionRequest() 1102 1112 { 1103 closeSession(); 1113 cleanupGuestSessionListener(); 1114 1115 closeGuestSession(); 1104 1116 } 1105 1117 1106 1118 void UIFileManagerGuestTable::sltCommitDataSignalReceived() 1107 1119 { 1108 m_comMachine.detach(); 1109 } 1110 1111 void UIFileManagerGuestTable::sltAdditionsChange() 1120 cleanAll(); 1121 if (!m_comMachine.isNull()) 1122 m_comMachine.detach(); 1123 } 1124 1125 void UIFileManagerGuestTable::sltAdditionsStateChange() 1112 1126 { 1113 1127 setSessionDependentWidgetsEnabled(isSessionPossible()); … … 1122 1136 } 1123 1137 1124 void UIFileManagerGuestTable::closeSession() 1125 { 1138 bool UIFileManagerGuestTable::openGuestSession(const QString &strUserName, const QString &strPassword) 1139 { 1140 if (m_comGuest.isNull()) 1141 { 1142 emit sigLogOutput("Guest reference is invalid", m_strTableName, FileManagerLogType_Error); 1143 return false; 1144 } 1145 1146 if (!isGuestAdditionsAvailable()) 1147 { 1148 emit sigLogOutput("Could not find Guest Additions", m_strTableName, FileManagerLogType_Error); 1149 postGuestSessionClosed(); 1150 if (m_pGuestSessionPanel) 1151 m_pGuestSessionPanel->markForError(true); 1152 return false; 1153 } 1154 1155 m_comGuestSession = m_comGuest.CreateSession(strUserName, strPassword, 1156 QString() /* Domain */, "File Manager Session"); 1157 if (m_comGuestSession.isNull()) 1158 { 1159 emit sigLogOutput("Could not create guest session", m_strTableName, FileManagerLogType_Error); 1160 return false; 1161 } 1162 1163 if (!m_comGuestSession.isOk()) 1164 { 1165 emit sigLogOutput(UIErrorString::formatErrorInfo(m_comGuestSession), m_strTableName, FileManagerLogType_Error); 1166 return false; 1167 } 1168 1169 QVector<KVBoxEventType> eventTypes(QVector<KVBoxEventType>() << KVBoxEventType_OnGuestSessionStateChanged); 1170 prepareListener(m_pQtSessionListener, m_comSessionListener, m_comGuestSession.GetEventSource(), eventTypes); 1171 qRegisterMetaType<CGuestSessionStateChangedEvent>(); 1172 connect(m_pQtSessionListener->getWrapped(), &UIMainEventListener::sigGuestSessionStatedChanged, 1173 this, &UIFileManagerGuestTable::sltGuestSessionStateChanged); 1174 1175 return true; 1176 } 1177 1178 void UIFileManagerGuestTable::closeGuestSession() 1179 { 1180 1126 1181 if (!m_comGuestSession.isNull()) 1182 { 1127 1183 m_comGuestSession.Close(); 1128 1184 m_comGuestSession.detach(); 1185 } 1129 1186 reset(); 1130 1131 if (!m_comSession.isNull())1132 m_comSession.UnlockMachine();1133 1134 cleanupGuestListener();1135 cleanupSessionListener();1136 1137 1187 emit sigLogOutput("Guest session is closed", m_strTableName, FileManagerLogType_Info); 1138 1188 postGuestSessionClosed(); 1139 1189 } 1140 1190 1141 1142 /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ 1143 /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ 1144 /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ 1145 #if 0 1146 1147 1148 1149 1150 1151 1152 void UIFileManager::sltCloseGuestSession() 1153 { 1154 if (!m_comGuestSession.isOk()) 1155 { 1156 emit sigLogOutput("Guest session is not valid", m_strTableName, FileManagerLogType_Error); 1157 postGuestSessionClosed(); 1158 return; 1159 } 1160 if (m_pGuestFileTable) 1161 m_pGuestFileTable->reset(); 1162 1163 if (m_comGuestSession.isOk() && m_pQtSessionListener && m_comSessionListener.isOk()) 1164 cleanupListener(m_pQtSessionListener, m_comSessionListener, m_comGuestSession.GetEventSource()); 1165 1166 m_comGuestSession.Close(); 1167 emit sigLogOutput("Guest session is closed", m_strTableName, FileManagerLogType_Info); 1168 postGuestSessionClosed(); 1169 } 1170 1171 1172 1173 void sltCreateGuestSession(QString strUserName, QString strPassword); 1174 void sltCloseGuestSession(); 1175 1176 1177 1178 void UIFileManager::sltCleanupListenerAndGuest() 1179 { 1180 if (m_comGuest.isOk() && m_pQtGuestListener && m_comGuestListener.isOk()) 1181 cleanupListener(m_pQtGuestListener, m_comGuestListener, m_comGuest.GetEventSource()); 1182 if (m_comGuestSession.isOk() && m_pQtSessionListener && m_comSessionListener.isOk()) 1183 cleanupListener(m_pQtSessionListener, m_comSessionListener, m_comGuestSession.GetEventSource()); 1184 1185 if (m_comGuestSession.isOk()) 1186 m_comGuestSession.Close(); 1187 } 1188 1189 #endif 1190 /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ 1191 /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ 1192 /*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ 1193 1194 1191 void UIFileManagerGuestTable::cleanAll() 1192 { 1193 cleanupConsoleListener(); 1194 cleanupGuestListener(); 1195 cleanupGuestSessionListener(); 1196 1197 closeGuestSession(); 1198 closeMachineSession(); 1199 } 1195 1200 1196 1201 -
trunk/src/VBox/Frontends/VirtualBox/src/guestctrl/UIFileManagerGuestTable.h
r92787 r92790 33 33 #include "CMachine.h" 34 34 #include "CSession.h" 35 #include "CConsole.h" 35 36 36 37 … … 101 102 void sltMachineStateChange(const QUuid &uMachineId, const KMachineState state); 102 103 void sltCommitDataSignalReceived(); 103 void sltAdditions Change();104 void sltAdditionsStateChange(); 104 105 105 106 private: … … 129 130 CEventSource comEventSource); 130 131 void cleanupGuestListener(); 131 void cleanupSessionListener(); 132 void cleanupGuestSessionListener(); 133 void cleanupConsoleListener(); 132 134 133 135 void prepareGuestSessionPanel(); 134 /** Creates a shared machine session, opens a guest session and registers event listeners. */ 135 bool openSession(const QString& strUserName, const QString& strPassword); 136 void closeSession(); 137 bool isGuestAdditionsAvailable(CGuest &guest); 136 137 138 bool openGuestSession(const QString& strUserName, const QString& strPassword); 139 void closeGuestSession(); 140 141 bool openMachineSession(); 142 bool closeMachineSession(); 143 138 144 bool isGuestAdditionsAvailable(); 139 145 … … 145 151 146 152 void initFileTable(); 153 void cleanAll(); 147 154 148 149 CGuest m_comGuest;150 C GuestSession m_comGuestSession;151 C Session m_comSession;152 C Machine m_comMachine;155 CGuest m_comGuest; 156 CGuestSession m_comGuestSession; 157 CSession m_comSession; 158 CMachine m_comMachine; 159 CConsole m_comConsole; 153 160 154 161 ComObjPtr<UIMainEventListenerImpl> m_pQtGuestListener; 155 162 ComObjPtr<UIMainEventListenerImpl> m_pQtSessionListener; 163 ComObjPtr<UIMainEventListenerImpl> m_pQtConsoleListener; 156 164 CEventListener m_comSessionListener; 157 165 CEventListener m_comGuestListener; 166 CEventListener m_comConsoleListener; 158 167 UIFileManagerGuestSessionPanel *m_pGuestSessionPanel; 159 168 CheckMachine m_enmCheckMachine;
Note:
See TracChangeset
for help on using the changeset viewer.