diff --git a/.hgtags b/.hgtags index f45d8381e9..7951e232af 100644 --- a/.hgtags +++ b/.hgtags @@ -72,35 +72,35 @@ b53a0576eec80614d7767ed72b40ed67aeff27c9 DRTVWR-38_2.5.2-release 461c8c65b5c799ddfe365422f9be9c0095d91e7d 2.6.0-beta1-tip 9e4641f4a7870c0f565a25a2971368d5a29516a1 2.6.0-beta2 9e4641f4a7870c0f565a25a2971368d5a29516a1 DRTVWR-41_2.6.0-beta2 -42f32494bac475d0737799346f6831558ae8bf5d 2.6.0-release -42f32494bac475d0737799346f6831558ae8bf5d DRTVWR-39_2.6.0-release c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-beta1 c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-start c5bdef3aaa2744626aef3c217ce29e1900d357b3 DRTVWR-43_2.6.1-beta1 -c9182ed77d427c759cfacf49a7b71a2e20d522aa 2.6.1-release -c9182ed77d427c759cfacf49a7b71a2e20d522aa DRTVWR-42_2.6.1-release 56b2778c743c2a964d82e1caf11084d76a87de2c 2.6.2-start d1203046bb653b763f835b04d184646949d8dd5c 2.6.2-beta1 d1203046bb653b763f835b04d184646949d8dd5c DRTVWR-45_2.6.2-beta1 -214180ad5714ce8392b82bbebcc92f4babd98300 2.6.2-release -214180ad5714ce8392b82bbebcc92f4babd98300 DRTVWR-44_2.6.2-release +42f32494bac475d0737799346f6831558ae8bf5d 2.6.0-release +42f32494bac475d0737799346f6831558ae8bf5d DRTVWR-39_2.6.0-release +c9182ed77d427c759cfacf49a7b71a2e20d522aa 2.6.1-release +c9182ed77d427c759cfacf49a7b71a2e20d522aa DRTVWR-42_2.6.1-release 52b2263ab28f0976c689fd0b76c55a9eb027cdbf end-of-develop.py ec32f1045e7c2644015245df3a9933620aa194b8 2.6.3-start d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc 2.6.3-beta1 d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc DRTVWR-47_2.6.3-beta1 0630e977504af5ea320c58d33cae4e1ddee793e9 2.6.3-beta2 0630e977504af5ea320c58d33cae4e1ddee793e9 DRTVWR-48_2.6.3-beta2 -8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release -8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release 3178e311da3a8739a85363665006ea3c4610cad4 dons-headless-hackathon-work +214180ad5714ce8392b82bbebcc92f4babd98300 2.6.2-release +214180ad5714ce8392b82bbebcc92f4babd98300 DRTVWR-44_2.6.2-release 7db558aaa7c176f2022b3e9cfe38ac72f6d1fccd 2.6.5-beta1 7db558aaa7c176f2022b3e9cfe38ac72f6d1fccd DRTVWR-50_2.6.5-beta1 +8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release +8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release 800cefce8d364ffdd2f383cbecb91294da3ea424 2.6.6-start bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 2.6.6-beta1 bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 DRTVWR-52_2.6.6-beta1 +5e349dbe9cc84ea5795af8aeb6d473a0af9d4953 2.6.8-start dac76a711da5f1489a01c1fa62ec97d99c25736d 2.6.6-release dac76a711da5f1489a01c1fa62ec97d99c25736d DRTVWR-51_2.6.6-release -5e349dbe9cc84ea5795af8aeb6d473a0af9d4953 2.6.8-start beafa8a9bd1d1b670b7523d865204dc4a4b38eef 2.6.8-beta1 beafa8a9bd1d1b670b7523d865204dc4a4b38eef DRTVWR-55_2.6.8-beta1 be2000b946f8cb3de5f44b2d419287d4c48ec4eb 2.6.8-release @@ -119,50 +119,50 @@ e67da2c6e3125966dd49eef98b36317afac1fcfe 2.6.9-start 9f79a6ed8fdcd2f3dac33ea6b3236eeb278dccfe 2.7.2-start e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb 2.7.2-beta1 e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb DRTVWR-63_2.7.2-beta1 +6a3e7e403bd19e45fdfc2fcc716867af3ab80861 2.7.3-start fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.1-release fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.2-release fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-60_2.7.1-release fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-62_2.7.2-release -6a3e7e403bd19e45fdfc2fcc716867af3ab80861 2.7.3-start 6af10678de4736222b2c3f7e010e984fb5b327de 2.7.4-start be963a4eef635542f9617d7f5fd22ba48fb71958 2.7.4-beta1 be963a4eef635542f9617d7f5fd22ba48fb71958 DRTVWR-67_2.7.4-beta1 -057f319dd8eccdf63a54d99686c68cdcb31b6abc 2.7.4-release -057f319dd8eccdf63a54d99686c68cdcb31b6abc DRTVWR-66_2.7.4-release 19a498fa62570f352d7d246f17e3c81cc1d82d8b 2.7.5-start 09984bfa6cae17e0f72d02b75c1b7393c65eecfc 2.7.5-beta1 09984bfa6cae17e0f72d02b75c1b7393c65eecfc DRTVWR-69_2.7.5-beta1 -6866d9df6efbd441c66451debd376d21211de39c 2.7.5-release -6866d9df6efbd441c66451debd376d21211de39c DRTVWR-68_2.7.5-release e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-beta1 e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-start e1ed60913230dd64269a7f7fc52cbc6004f6d52c DRTVWR-71_2.8.0-beta1 -493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release -493d9127ee50e84ba08a736a65a23ca86f7a5b01 DRTVWR-70_2.8.0-release +057f319dd8eccdf63a54d99686c68cdcb31b6abc 2.7.4-release +057f319dd8eccdf63a54d99686c68cdcb31b6abc DRTVWR-66_2.7.4-release +6866d9df6efbd441c66451debd376d21211de39c 2.7.5-release +6866d9df6efbd441c66451debd376d21211de39c DRTVWR-68_2.7.5-release 502f6a5deca9365ddae57db4f1e30172668e171e 2.8.1-start 2c7e459e0c883f8e406b932e41e60097e9ee077e 2.8.1-beta1 2c7e459e0c883f8e406b932e41e60097e9ee077e DRTVWR-73_2.8.1-beta1 +493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release +493d9127ee50e84ba08a736a65a23ca86f7a5b01 DRTVWR-70_2.8.0-release +54bc7823ad4e3a436fef79710f685a7372bbf795 2.8.2-start +ac0f1a132d35c02a58861d37cca75b0429ac9137 2.8.3-start 29e93d7e19991011bd12b5748142b11a5dcb4370 2.8.1-release 29e93d7e19991011bd12b5748142b11a5dcb4370 DRTVWR-72_2.8.1-release 4780e3bd2b3042f91be3426151f28c30d199bb3b 2.8.1-hotfix 4780e3bd2b3042f91be3426151f28c30d199bb3b DRTVWR-76_2.8.1-hotfix -54bc7823ad4e3a436fef79710f685a7372bbf795 2.8.2-start -ac0f1a132d35c02a58861d37cca75b0429ac9137 2.8.3-start 599677276b227357140dda35bea4a2c18e2e67b5 2.8.3-beta1 599677276b227357140dda35bea4a2c18e2e67b5 DRTVWR-75_2.8.3-beta1 -fb85792b84bf28428889c4cc966469d92e5dac4c 2.8.3-release -fb85792b84bf28428889c4cc966469d92e5dac4c DRTVWR-74_2.8.3-release 6b678ea52f90d5c14181661dcd2546e25bde483e 3.0.0-start b0be6ce3adfef3a014a2389d360539f8a86c5439 3.0.0-beta1 b0be6ce3adfef3a014a2389d360539f8a86c5439 DRTVWR-78_3.0.0-beta1 -1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release -1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-77_3.0.0-release +fb85792b84bf28428889c4cc966469d92e5dac4c 2.8.3-release +fb85792b84bf28428889c4cc966469d92e5dac4c DRTVWR-74_2.8.3-release 82a2079ffcb57ecb1b3849cb41376b443e1eb912 3.0.1-start 364fd63517fbacbbcb9129d096187171ba8c9e48 3.0.1-beta1 364fd63517fbacbbcb9129d096187171ba8c9e48 DRTVWR-81_3.0.1-beta1 f2412ecd6740803ea9452f1d17fd872e263a0df7 3.0.2-start 42784bf50fa01974bada2a1af3892ee09c93fcda 3.0.2-beta1 42784bf50fa01974bada2a1af3892ee09c93fcda DRTVWR-83_3.0.2-beta1 +1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release +1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-77_3.0.0-release e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e 3.0.2-beta2 e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e DRTVWR-86_3.0.2-beta2 b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start @@ -170,9 +170,9 @@ b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start 6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 DRTVWR-85_3.0.3-beta1 61aa7974df089e8621fe9a4c69bcdefdb3cc208a 3.0.3-beta2 61aa7974df089e8621fe9a4c69bcdefdb3cc208a DRTVWR-89_3.0.3-beta2 +586907287be581817b2422b5137971b22d54ea48 3.0.4-start 0496d2f74043cf4e6058e76ac3db03d44cff42ce 3.0.3-release 0496d2f74043cf4e6058e76ac3db03d44cff42ce DRTVWR-84_3.0.3-release -586907287be581817b2422b5137971b22d54ea48 3.0.4-start 92a3aa04775438226399b19deee12ac3b5a62838 3.0.5-start c7282e59f374ee904bd793c3c444455e3399b0c5 3.1.0-start 2657fa785bbfac115852c41bd0adaff74c2ad5da 3.1.0-beta1 @@ -193,11 +193,11 @@ e440cd1dfbd128d7d5467019e497f7f803640ad6 DRTVWR-95_3.2.0-beta1 c4911ec8cd81e676dfd2af438b3e065407a94a7a 3.2.1-start 9e390d76807fa70d356b8716fb83b8ce42a629ef 3.2.1-beta1 9e390d76807fa70d356b8716fb83b8ce42a629ef DRTVWR-100_3.2.1-beta1 -a8c7030d6845186fac7c188be4323a0e887b4184 3.2.1-release -a8c7030d6845186fac7c188be4323a0e887b4184 DRTVWR-99_3.2.1-release 40b46edba007d15d0059c80864b708b99c1da368 3.2.2-start 523df3e67378541498d516d52af4402176a26bac 3.2.2-beta1 523df3e67378541498d516d52af4402176a26bac DRTVWR-102_3.2.2-beta1 +a8c7030d6845186fac7c188be4323a0e887b4184 3.2.1-release +a8c7030d6845186fac7c188be4323a0e887b4184 DRTVWR-99_3.2.1-release 80f3e30d8aa4d8f674a48bd742aaa6d8e9eae0b5 3.2.3-start 3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-beta1 3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-start @@ -248,68 +248,57 @@ bb9932a7a5fd00edf52d95f354e3b37ae6a942db DRTVWR-156 6414ecdabc5d89515b08d1f872cf923ed3a5523a DRTVWR-148 2a3965b3ad202df7ea25d2be689291bb14a1280e DRTVWR-155 24a7281bef42bd4430ceb25db8b195449c2c7de3 DRTVWR-153 -a716684aa7c07c440b1de5815b8a1f3dd3fd8bfb DRTVWR-159 -9a78ac13f047056f788c4734dd91aebfe30970e3 DRTVWR-157 5910f8063a7e1ddddf504c2f35ca831cc5e8f469 DRTVWR-160 f0a174c2adb4bc39b16722a61d7eeb4f2a1d4843 3.3.3-beta1 f0a174c2adb4bc39b16722a61d7eeb4f2a1d4843 DRTVWR-144 -089e5c84b2dece68f2b016c842ef9b5de4786842 DRTVWR-161 -600f3b3920d94de805ac6dc8bb6def9c069dd360 DRTVWR-162 -c08e2ac17a99973b2a94477659220b99b8847ae2 DRTVWR-163 2d6c0634b11e6f3df11002b8510a72a0433da00a DRTVWR-164 +600f3b3920d94de805ac6dc8bb6def9c069dd360 DRTVWR-162 80b5e5e9775966d3839331ffa7a16a60f9d7c930 DRTVWR-165 fdcc08a4f20ae9bb060f4693c8980d216534efdf 3.3.3-beta2 af5f3e43e6e4424b1da19d9e16f6b853a7b822ed DRTVWR-169 4b3c68199a86cabaa5d9466d7b0f7e141e901d7a 3.3.3-beta3 6428242e124b523813bfaf4c45b3d422f0298c81 3.3.3-release +a716684aa7c07c440b1de5815b8a1f3dd3fd8bfb DRTVWR-159 +9a78ac13f047056f788c4734dd91aebfe30970e3 DRTVWR-157 +089e5c84b2dece68f2b016c842ef9b5de4786842 DRTVWR-161 +c08e2ac17a99973b2a94477659220b99b8847ae2 DRTVWR-163 b9d0170b62eb1c7c3adaa37a0b13a833e5e659f9 DRTVWR-171 050e48759337249130f684b4a21080b683f61732 DRTVWR-168 09ef7fd1b0781f33b8a3a9af6236b7bcb4831910 DRTVWR-170 f87bfbe0b62d26f451d02a47c80ebef6b9168fc2 DRTVWR-158 f91d003091a61937a044652c4c674447f7dcbb7a 3.3.4-beta1 -005dfe5c4c377207d065fb27858d2eb0b53b143a DRTVWR-167 bce218b2b45b730b22cc51e4807aa8b571cadef3 DRTVWR-173 cbea6356ce9cb0c313b6777f10c5c14783264fcc DRTVWR-174 82b5330bc8b17d0d4b598832e9c5a92e90075682 3.3.4-beta2 57d221de3df94f90b55204313c2cef044a3c0ae2 DRTVWR-176 eb539c65e6ee26eea2bf373af2d0f4b52dc91289 DRTVWR-177 a8057e1b9a1246b434a27405be35e030f7d28b0c 3.3.4-beta3 -888768f162d2c0a8de1dcc5fb9a08bd8bd120a6b DRTVWR-175 4281aa899fb2cedb7a9ca7ce91c5c29d4aa69594 DRTVWR-180 5c08e1d8edd871807153603b690e3ee9dbb548aa DRTVWR-183 6c75f220b103db1420919c8b635fe53e2177f318 3.3.4-beta4 9cd174d3a54d93d409a7c346a15b8bfb40fc58f4 DRTVWR-184 ab2ffc547c8a8950ff187c4f6c95e5334fab597b 3.3.4-beta5 28e100d0379a2b0710c57647a28fc5239d3d7b99 3.3.4-release +005dfe5c4c377207d065fb27858d2eb0b53b143a DRTVWR-167 +888768f162d2c0a8de1dcc5fb9a08bd8bd120a6b DRTVWR-175 a8b3eca451a9eaab59987efb0ab1c4217e3f2dcc DRTVWR-182 1f27cdfdc54246484f8afbbe42ce48e954175cbd 3.4.0-beta1 -81f6b745ef27f5915fd07f988fdec9944f2bb73e DRTVWR-186 -47f0d08ba7ade0a3905074009067c6d3df7e16ae DRTVWR-190 -cc953f00956be52cc64c30637bbeec310eea603f DRTVWR-181 -c04e68e1b0034fd0a20815ae24c77e5f8428e822 DRTVWR-188 9ee9387789701d597130f879d9011a4958753862 DRTVWR-189 +47f0d08ba7ade0a3905074009067c6d3df7e16ae DRTVWR-190 421126293dcbde918e0da027ca0ab9deb5b4fbf2 DRTVWR-192 -4b2c52aecb7a75de31dbb12d9f5b9a251d8707be DRTVWR-191 33a2fc7a910ae29ff8b4850316ed7fbff9f64d33 DRTVWR-195 e9732c739c8a72a590216951505ea9c76a526a84 DRTVWR-193 -78ca0bbf43a92e8914d4cfa87d69a6717ef7d4cf DRTVWR-194 7602f61c804a512764e349c034c02ddabeefebc4 DRTVWR-196 ae5c83dd61d2d37c45f1d5b8bf2b036d87599f1b DRTVWR-198 507bdfbd6bf844a511c1ffeda4baa80016ed1346 DRTVWR-197 b1dbb1a83f48f93f6f878cff9e52d2cb635e145c 3.4.0-beta2 37402e2b19af970d51b0a814d79892cc5647532b DRTVWR-200 182a9bf30e81070361bb020a78003b1cf398e79c 3.4.0-beta3 -248f4acd92a706c79e842bc83d80baa7369c0c2e DRTVWR-203 6dfb0fba782c9233dd95f24ec48146db0d3f210b DRTVWR-199 7c9102fb998885621919f2474a002c35b583539b 3.3.4-release2 7649a3dff5ec22d3727377e5f02efd0f421e4cb5 DRTVWR-201 84fb70dfe3444e75a44fb4bee43e2fc8221cebdd 3.4.0-beta4 -de3be913f68813a9bac7d1c671fef96d1159bcd6 DRTVWR-202 -092a9effbedd1a0276fa5ced520992ce00f96fbf CHUI-PV-0 573e863be2f26d3687161def4b9fea9b7038dda8 3.4.0-beta5 -34dbbe2b00afe90352d3acf8290eb10ab90d1c8b oz-build-test-tag -6ee71714935ffcd159db3d4f5800c1929aac54e1 DRTVWR-205 -7b22c612fc756e0ea63b10b163e81d107f85dbf8 DRTVWR-206 8c9085066c78ed5f6c9379dc054c82a6fcdb1851 DRTVWR-207 351eea5f9dc192fc5ddea3b02958de97677a0a12 3.3.4-release3 af7b28e75bd5a629cd9e0dc46fb3f1757626f493 DRTVWR-212 @@ -320,7 +309,6 @@ ceed0b65a69f1eac20d523e0203320a32f9a3f3c DRTVWR-215 97977c67245f52db20eb15f1918cc0f24778cabc 3.4.0-release 5adb2b8f96c3cac88ad7c7d996d707f1b29df336 3.4.1-beta1 b3f74858a1c8720c82d0978f3877a3fc8ba459ec 3.4.1-beta1a -b61afe175b829c149d369524a4e974dfda99facf DRTVWR-219 2b779f233ee6f38c89cb921650c773a96e63da92 DRTVWR-220 0b9d95f4bfb6867cbf56eaec51633b0da2f1262d DRTVWR-221 e6e553761829dc0270eaaa712b7cb0622535b076 3.4.1-beta3 @@ -345,31 +333,36 @@ baf97f06ae17223614c5e31aa42e71d87cff07fe DRTVWR-236 b2f21e3442542283a80e7eaebae9f833e5a927b6 DRTVWR-237 3f9be82de642d468c5fc272cb9d96b46b5498402 3.4.1-beta12 e59ffd3fe0838ae6b09b242a6e9df71761b88f41 3.4.1-release +81f6b745ef27f5915fd07f988fdec9944f2bb73e DRTVWR-186 +cc953f00956be52cc64c30637bbeec310eea603f DRTVWR-181 +c04e68e1b0034fd0a20815ae24c77e5f8428e822 DRTVWR-188 +4b2c52aecb7a75de31dbb12d9f5b9a251d8707be DRTVWR-191 +78ca0bbf43a92e8914d4cfa87d69a6717ef7d4cf DRTVWR-194 +248f4acd92a706c79e842bc83d80baa7369c0c2e DRTVWR-203 +de3be913f68813a9bac7d1c671fef96d1159bcd6 DRTVWR-202 +34dbbe2b00afe90352d3acf8290eb10ab90d1c8b oz-build-test-tag +6ee71714935ffcd159db3d4f5800c1929aac54e1 DRTVWR-205 +7b22c612fc756e0ea63b10b163e81d107f85dbf8 DRTVWR-206 +b61afe175b829c149d369524a4e974dfda99facf DRTVWR-219 32896d5e920ca9a29256ff3b747c2e99752aa5ae DRTVWR-217 704bbae7b182a1f2811a47a054e680522966f54a 3.4.2-beta1 -d799593b53ed733862e9a13871e318e886469377 DRTVWR-208 -e497dcde7a3653e384eb223a8a460030e89c294c DRTVWR-223 288539fc0408ed4b69a99665de33bbbc2c3c08fe DRTVWR-216 e664473c16df1d82ffaff382e7b3e023da202d52 3.4.2-beta2 -93ab02d83f51e30a3cabad98aff89601befd9413 DRTVWR-240 0891d7a773a31397dcad48be3fa66531d567a821 DRTVWR-242 710785535362b3cb801b6a3dc4703be3373bd0cd 3.4.2-beta3 -2aa72e3372a83dece4df9cf72fb1e7c34f90b5e3 DRTVWR-209 -f7bedce18ad52283e6072814db23318907261487 DRTVWR-238 -7b64c96fbcadf360bd2feaae19d330166b70877c DRTVWR-210 e9a5886052433d5db9e504ffaca10890f9932979 DRTVWR-243 73b84b9864dc650fe7c8fc9f52361450f0849004 3.4.2-beta4 16310aabccf315870f7cc9bf966926c0ad6954fa 3.4.2-release +d799593b53ed733862e9a13871e318e886469377 DRTVWR-208 +e497dcde7a3653e384eb223a8a460030e89c294c DRTVWR-223 +93ab02d83f51e30a3cabad98aff89601befd9413 DRTVWR-240 +2aa72e3372a83dece4df9cf72fb1e7c34f90b5e3 DRTVWR-209 +f7bedce18ad52283e6072814db23318907261487 DRTVWR-238 +7b64c96fbcadf360bd2feaae19d330166b70877c DRTVWR-210 5e4e4128b256525bafc07a62e35ae8527aaa9c9d DRTVWR-241 f1d3b3fcab28ed9ea532bf50db0ba96f5c8cc8e9 DRTVWR-232 4918b150e75df6b516fb6c2616d32043fa6b4cac DRTVWR-245 94ab2b49458ab372a95d2d6949fdf574f413068d 3.4.3-beta1 -4c3460cb1fb7c6da9965e09c734d282a8e9c81f0 DRTVWR-229 -f4481df42f9a4a92bf475a80f0c51d1a4bbdfd59 DRTVWR-246 -39c5204b6e800983a41ccac8ad6dc993120197c6 DRTVWR-247 -7c7d57d393e8ae7b61623279de06eb4a62ccae6a DRTVWR-249 -f72b50ef168c159d6e79e97aa2bcafaf8577ab99 DRTVWR-230 -b418be80903520c492e1173f3afbc4021cad5d07 DRTVWR-255 965b9a35e260c0f53be1a25f0db7abc8a67eaf47 DRTVWR-252 bb10adc4f76cf0067fca7075146f00cdc0740e9d DRTVWR-251 ab0aa2f6ba22b52fed30a2337197f589156edc75 DRTVWR-253 @@ -378,25 +371,31 @@ ab0aa2f6ba22b52fed30a2337197f589156edc75 DRTVWR-253 44e764a6ac9e672a4f3bce821a4b6a218590c374 DRTVWR-258 c23d734065ed593b2413385aecd8366d8e0ee96b DRTVWR-257 452ce96d4046dc05a3ecaecc203e2cc8ddd72e76 DRTVWR-259 -9aa1aa9f1fe13c194695a0b8f0af298296241dc2 DRTVWR-260 daca610d840625b5bebb966a57cb49581852c417 DRTVWR-265 9afbdc4e24cc04feacfb2b7a10b78a64f780901a DRTVWR-266 73280db02501f5ad041fc18b1eba68e73a81996c DRTVWR-267 870e2d79e0063fda87187f17bbc2747766733194 3.4.3-beta3 0a2ca6546b499239afeb66d17b2fadbcdbe36ab1 3.4.3-release +4c3460cb1fb7c6da9965e09c734d282a8e9c81f0 DRTVWR-229 +f4481df42f9a4a92bf475a80f0c51d1a4bbdfd59 DRTVWR-246 +39c5204b6e800983a41ccac8ad6dc993120197c6 DRTVWR-247 +7c7d57d393e8ae7b61623279de06eb4a62ccae6a DRTVWR-249 +f72b50ef168c159d6e79e97aa2bcafaf8577ab99 DRTVWR-230 +b418be80903520c492e1173f3afbc4021cad5d07 DRTVWR-255 +9aa1aa9f1fe13c194695a0b8f0af298296241dc2 DRTVWR-260 84fbaf2d4141bd161731430e760949dc787ca206 DRTVWR-244 083d2d36b5bb1c54fc3dd7caac0e7ac381a9cef0 3.4.4-beta1 -391a8c74cec7275c5d26c85ad108d4782a3e3dd9 DRTVWR-268 b634dec987c16e8c9c938e11e52591d9ead8fa9b DRTVWR-270 cd39255bd23330fd30c04105f2811e941d8524fe 3.4.4-beta2 2c4011bbc2b15b82198fd8b51f3a9fe765a08c4d DRTVWR-271 2f8a3ef687bc55828abcb17ac1ad7cde70536d7e 3.4.4-beta3 35cfd4cf5b895fa776592f2e630e330be7f0604e DRTVWR-273 -a36f1f354b02aa6e448ca13685de167d0a0a3d03 DRTVWR-272 -37dba00ad820de3a808d4039396b162a9c275b3e DRTVWR-269 c374035d459af3c03dea2dd90880dfc25de64706 DRTVWR-275 05d9f1dd7a954069af2a33abedb7713fa36a04cb 3.4.4-beta4 e1bb1ae7d8b12faeb37933a737c199cc9b9f89cc 3.4.4-release +391a8c74cec7275c5d26c85ad108d4782a3e3dd9 DRTVWR-268 +a36f1f354b02aa6e448ca13685de167d0a0a3d03 DRTVWR-272 +37dba00ad820de3a808d4039396b162a9c275b3e DRTVWR-269 7c6dfdc1b7a2ce0d8e3a8f3ce3058547ea065c0f DRTVWR-250 b9ff9730daa53a541925300cbd02bb14575a5705 DRTVWR-277 af6b711a97073431953b55ee808aaa09900c27e5 DRTVWR-276 @@ -406,8 +405,6 @@ c296133849d1f103c0e2abc41e6599daed00b67b DRTVWR-280 5df4802bec93c8d0a509946d826bb4c50c5442ec DRTVWR-281 7c1c33ba4cfd2d15ca51cc1ac440eca551331a4a DRTVWR-283 6b9c7dbebef793230d64e1b452577c8b142d4143 3.4.5-beta2 -37947e4f771f001b551581bf7cd0051c3153beed DRTVWR-282 -6482cceb91cda68b799f3e6cdc66d33bf123547a DRTVWR-284 ccf991e02dc2f63fb646324230d54832683f4a9b DRTVWR-286 2d849850558a5a0324b398d1c102d30bcbdfb88f DRTVWR-287 e06898df8644fe567bee94f817d03abc1c380993 3.4.5-beta3 @@ -420,6 +417,17 @@ b23419a2748483c98f3b84b630468a21c88feba5 DRTVWR-292 0a5d409161ef2a89b28c9a741051dd2dedc707d6 DRTVWR-297 852b69ef0b5fe6b13b69cc2217282cc64de6afab 3.4.5-beta5 a49c715243a36a8a380504d14cb7416b3039c956 3.4.5-release +37947e4f771f001b551581bf7cd0051c3153beed DRTVWR-282 +6482cceb91cda68b799f3e6cdc66d33bf123547a DRTVWR-284 +092a9effbedd1a0276fa5ced520992ce00f96fbf CHUI-PV-0 279ef1dfc9b749a6cc499cf190fec0c090b6d682 DRTVWR-288 9b19edaf1d8ddf435f60fbbb444dd25db8f63953 3.5.0-beta1 c6b3561c7d7ad365eeba669db54eb57b5149ce75 3.5.0-beta2 +6d91ffd77bf2a20f18a2175eb7579da880ae12ac DRTVWR-302 +f6ca5bb75bca975ff0bc77e71e615f6478c4559c 3.5.0-beta3 +910b5fad950e343b58229f5a0aefa7729b9308b3 DRTVWR-303 +53cffdde0b3cc367ba9bb6abd5c83ae14df5e882 3.5.0-beta4 +4d5f6234dc59a0fb6ead5e02c7d343a0610e0488 DRTVWR-304 +dd058a6093c493120d67c8e02c812c0f7b2d3db0 3.5.0-beta5 +fd6b510e83f56830e45670c428653134899d3e25 DRTVWR-305 +55339537d99afc394d1bb7fdb7d074bf321ca62f 3.5.0-beta6 diff --git a/doc/contributions.txt b/doc/contributions.txt index 10c935f9bb..32dd3c1a2e 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -744,6 +744,7 @@ Marc Claridge Marc2 Sands Marianne McCann Marine Kelley + CHUIBUG-134 STORM-281 MartinRJ Fayray STORM-1844 diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 647512eb2e..8772779645 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -599,6 +599,11 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch if(!fgi) { fgi = mFontFreetype->getGlyphInfo(wch); + + if (NULL == fgi) + { + return 0; + } } // account for glyphs that run beyond the starting point for the next glyphs diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 09e451c62a..fd668f2d34 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -597,11 +597,6 @@ bool LLGLManager::initGL() if (mGLVendor.substr(0,4) == "ATI ") { mGLVendorShort = "ATI"; - BOOL mobile = FALSE; - if (mGLRenderer.find("MOBILITY") != std::string::npos) - { - mobile = TRUE; - } mIsATI = TRUE; #if LL_WINDOWS && !LL_MESA_HEADLESS @@ -1489,9 +1484,7 @@ void assert_glerror() void clear_glerror() { - // Create or update texture to be used with this data - GLenum error; - error = glGetError(); + glGetError(); } /////////////////////////////////////////////////////////////// diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp index 8e9c6555c3..9e48dcde7e 100644 --- a/indra/llui/llchatentry.cpp +++ b/indra/llui/llchatentry.cpp @@ -169,6 +169,15 @@ BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask) { BOOL handled = FALSE; + // In the case of a chat entry, pressing RETURN when something is selected + // should NOT erase the selection (unlike a notecard, for example) + if (key == KEY_RETURN) + { + endOfDoc(); + startSelection(); + endSelection(); + } + LLTextEditor::handleSpecialKey(key, mask); switch(key) diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 27dd7f5b32..09e27a264a 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1621,7 +1621,7 @@ void LLFloater::bringToFront( S32 x, S32 y ) // virtual -void LLFloater::setVisibleAndFrontmost(BOOL take_focus) +void LLFloater::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key) { LLMultiFloater* hostp = getHost(); if (hostp) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index cb5bf28db3..4dba1e645f 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -305,7 +305,7 @@ public: /*virtual*/ void handleVisibilityChange ( BOOL new_visibility ); // do not override void setFrontmost(BOOL take_focus = TRUE); - virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE); + virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); // Defaults to false. virtual BOOL canSaveAs() const { return FALSE; } diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index c20d863612..1cdddf0d5b 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -488,12 +488,12 @@ void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& { host->setMinimized(FALSE); instance->openFloater(key); - instance->setVisibleAndFrontmost(); + instance->setVisibleAndFrontmost(true, key); } else if (!instance->getVisible()) { instance->openFloater(key); - instance->setVisibleAndFrontmost(); + instance->setVisibleAndFrontmost(true, key); instance->setFocus(TRUE); } else @@ -506,16 +506,16 @@ void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& if (instance->isMinimized()) { instance->setMinimized(FALSE); - instance->setVisibleAndFrontmost(); + instance->setVisibleAndFrontmost(true, key); } else if (!instance->isShown()) { instance->openFloater(key); - instance->setVisibleAndFrontmost(); + instance->setVisibleAndFrontmost(true, key); } else if (!instance->isFrontmost()) { - instance->setVisibleAndFrontmost(); + instance->setVisibleAndFrontmost(true, key); } else { diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 2e64be89fa..6976b06a92 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -202,6 +202,14 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) LLLineEditor::~LLLineEditor() { mCommitOnFocusLost = FALSE; + + // Make sure no context menu linger around once the widget is deleted + LLContextMenu* menu = static_cast(mContextMenuHandle.get()); + if (menu) + { + menu->hide(); + } + setContextMenu(NULL); // calls onCommit() while LLLineEditor still valid gFocusMgr.releaseFocusIfNeeded( this ); diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 8b9fb47d5c..7f04c92b27 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1801,6 +1801,9 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) // (N.B. callbacks don't take const refs as id is local scope) bool is_group = (mContextMenuType == MENU_GROUP); LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("Url.ShowProfile", boost::bind(&LLScrollListCtrl::showProfile, id, is_group)); + registrar.add("Url.SendIM", boost::bind(&LLScrollListCtrl::sendIM, id)); + registrar.add("Url.AddFriend", boost::bind(&LLScrollListCtrl::addFriend, id)); registrar.add("Url.Execute", boost::bind(&LLScrollListCtrl::showNameDetails, id, is_group)); registrar.add("Url.CopyLabel", boost::bind(&LLScrollListCtrl::copyNameToClipboard, id, is_group)); registrar.add("Url.CopyUrl", boost::bind(&LLScrollListCtrl::copySLURLToClipboard, id, is_group)); @@ -1821,11 +1824,33 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) return FALSE; } -void LLScrollListCtrl::showNameDetails(std::string id, bool is_group) +void LLScrollListCtrl::showProfile(std::string id, bool is_group) { // show the resident's profile or the group profile std::string sltype = is_group ? "group" : "agent"; std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about"; + LLUrlAction::showProfile(slurl); +} + +void LLScrollListCtrl::sendIM(std::string id) +{ + // send im to the resident + std::string slurl = "secondlife:///app/agent/" + id + "/about"; + LLUrlAction::sendIM(slurl); +} + +void LLScrollListCtrl::addFriend(std::string id) +{ + // add resident to friends list + std::string slurl = "secondlife:///app/agent/" + id + "/about"; + LLUrlAction::addFriend(slurl); +} + +void LLScrollListCtrl::showNameDetails(std::string id, bool is_group) +{ + // open the resident's details or the group details + std::string sltype = is_group ? "group" : "agent"; + std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about"; LLUrlAction::clickAction(slurl); } diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 38450b6313..8fa06cc499 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -430,6 +430,9 @@ private: BOOL setSort(S32 column, BOOL ascending); S32 getLinesPerPage(); + static void showProfile(std::string id, bool is_group); + static void sendIM(std::string id); + static void addFriend(std::string id); static void showNameDetails(std::string id, bool is_group); static void copyNameToClipboard(std::string id, bool is_group); static void copySLURLToClipboard(std::string id, bool is_group); diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 0c43a571b8..6f895ed939 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -1483,16 +1483,22 @@ BOOL LLTabContainer::setTab(S32 which) for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { LLTabTuple* tuple = *iter; - if (!tuple) - continue; BOOL is_selected = ( tuple == selected_tuple ); - tuple->mButton->setUseEllipses(mUseTabEllipses); - tuple->mButton->setHAlign(mFontHalign); - tuple->mTabPanel->setVisible( is_selected ); -// tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here. - tuple->mButton->setToggleState( is_selected ); - // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs - tuple->mButton->setTabStop( is_selected ); + + // Although the selected tab must be complete, we may have hollow LLTabTuple tucked in the list + if (tuple->mButton) + { + tuple->mButton->setUseEllipses(mUseTabEllipses); + tuple->mButton->setHAlign(mFontHalign); + tuple->mButton->setToggleState( is_selected ); + // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs + tuple->mButton->setTabStop( is_selected ); + } + if (tuple->mTabPanel) + { + tuple->mTabPanel->setVisible( is_selected ); + //tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here. + } if (is_selected) { @@ -1563,8 +1569,7 @@ BOOL LLTabContainer::selectTabByName(const std::string& name) LLPanel* panel = getPanelByName(name); if (!panel) { - llwarns << "LLTabContainer::selectTabByName(" - << name << ") failed" << llendl; + llwarns << "LLTabContainer::selectTabByName(" << name << ") failed" << llendl; return FALSE; } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 4bb819a7f6..270d5294f9 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -359,7 +359,6 @@ void LLTextBase::drawSelectionBackground() S32 selection_left = llmin( mSelectionStart, mSelectionEnd ); S32 selection_right = llmax( mSelectionStart, mSelectionEnd ); - LLRect selection_rect = mVisibleTextRect; // Skip through the lines we aren't drawing. LLRect content_display_rect = getVisibleDocumentRect(); @@ -1086,7 +1085,14 @@ BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask) BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask) { - mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL); + //Don't start triple click timer if user have clicked on scrollbar + mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect(); + if (x >= mVisibleTextRect.mLeft && x <= mVisibleTextRect.mRight + && y >= mVisibleTextRect.mBottom && y <= mVisibleTextRect.mTop) + { + mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL); + } + LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y); if (cur_segment && cur_segment->handleDoubleClick(x, y, mask)) { @@ -1912,6 +1918,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url)); registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url)); registrar.add("Url.SendIM", boost::bind(&LLUrlAction::sendIM, url)); + registrar.add("Url.AddFriend", boost::bind(&LLUrlAction::addFriend, url)); registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url)); registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url)); registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); @@ -2330,7 +2337,6 @@ const LLWString& LLTextBase::getWText() const S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, bool hit_past_end_of_line) const { // Figure out which line we're nearest to. - LLRect visible_region = getVisibleDocumentRect(); LLRect doc_rect = mDocumentView->getRect(); S32 doc_y = local_y - doc_rect.mBottom; @@ -3195,7 +3201,23 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin LLFontGL::EWordWrapStyle word_wrap_style = (line_offset == 0) ? LLFontGL::WORD_BOUNDARY_IF_POSSIBLE : LLFontGL::ONLY_WORD_BOUNDARIES; - S32 num_chars = mStyle->getFont()->maxDrawableChars(text.c_str() + segment_offset + mStart, + + + LLWString offsetString(text.c_str() + segment_offset + mStart); + + if(getLength() < segment_offset + mStart) + { + llerrs << "getLength() < segment_offset + mStart\t getLength()\t" << getLength() << "\tsegment_offset:\t" + << segment_offset << "\tmStart:\t" << mStart << "\tsegments\t" << mEditor.mSegments.size() << "\tmax_chars\t" << max_chars << llendl; + } + + if(offsetString.length() + 1 < max_chars) + { + llerrs << "offsetString.length() + 1 < max_chars\t max_chars:\t" << max_chars << "\toffsetString.length():\t" << offsetString.length() + << getLength() << "\tsegment_offset:\t" << segment_offset << "\tmStart:\t" << mStart << "\tsegments\t" << mEditor.mSegments.size() << llendl; + } + + S32 num_chars = mStyle->getFont()->maxDrawableChars(offsetString.c_str(), (F32)num_pixels, max_chars, word_wrap_style); diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 2f120479d9..d5e08fa29b 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2515,7 +2515,6 @@ void LLTextEditor::updateSegments() mKeywords.findSegments(&segment_list, getWText(), mDefaultColor.get(), *this); clearSegments(); - segment_set_t::iterator insert_it = mSegments.begin(); for (segment_vec_t::iterator list_it = segment_list.begin(); list_it != segment_list.end(); ++list_it) { insertSegment(*list_it); diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index b9256dd890..1c74395c66 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -1059,10 +1059,9 @@ BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, // Convert drag position into insert position and rank if (!isReadOnly() && handled && !drop) { - LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; - LLAssetType::EType type = inv_item->getType(); - if (type == LLAssetType::AT_WIDGET) + if (cargo_type == DAD_WIDGET) { + LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; LLCommandId dragged_command(inv_item->getUUID()); int orig_rank = getRankFromPosition(dragged_command); mDragRank = getRankFromPosition(x, y); diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index fd872eca4b..f51aeaec13 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -24,7 +24,6 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - #include "linden_common.h" #include "llurlaction.h" @@ -32,6 +31,7 @@ #include "llwindow.h" #include "llurlregistry.h" + // global state for the callback functions LLUrlAction::url_callback_t LLUrlAction::sOpenURLCallback; LLUrlAction::url_callback_t LLUrlAction::sOpenURLInternalCallback; @@ -158,16 +158,33 @@ void LLUrlAction::showProfile(std::string url) } } -void LLUrlAction::sendIM(std::string url) +std::string LLUrlAction::getUserID(std::string url) { LLURI uri(url); LLSD path_array = uri.pathArray(); + std::string id_str; if (path_array.size() == 4) { - std::string id_str = path_array.get(2).asString(); - if (LLUUID::validate(id_str)) - { - executeSLURL("secondlife:///app/agent/" + id_str + "/im"); - } + id_str = path_array.get(2).asString(); + } + return id_str; +} + +void LLUrlAction::sendIM(std::string url) +{ + std::string id_str = getUserID(url); + if (LLUUID::validate(id_str)) + { + executeSLURL("secondlife:///app/agent/" + id_str + "/im"); } } + +void LLUrlAction::addFriend(std::string url) +{ + std::string id_str = getUserID(url); + if (LLUUID::validate(id_str)) + { + executeSLURL("secondlife:///app/agent/" + id_str + "/requestfriend"); + } +} + diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index f5f2ceba72..e31cd71a20 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -76,7 +76,9 @@ public: /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile static void showProfile(std::string url); + static std::string getUserID(std::string url); static void sendIM(std::string url); + static void addFriend(std::string url); /// specify the callbacks to enable this class's functionality typedef boost::function url_callback_t; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 79376f7467..4c305e1d60 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1584,6 +1584,28 @@ Value 0 + ChatLoadGroupMaxMembers + + Comment + Max number of active members we'll show up for an unresponsive group + Persist + 1 + Type + S32 + Value + 100 + + ChatLoadGroupTimeout + + Comment + Time we give the server to send group participants before we hit the server for group info (seconds) + Persist + 1 + Type + F32 + Value + 10.0 + ChatOnlineNotification Comment @@ -1694,17 +1716,6 @@ Value 131073 - NearbyChatIsNotTornOff - - Comment - saving torn-off state of the nearby chat between sessions - Persist - 1 - Type - Boolean - Value - 1 - CloseChatOnReturn Comment @@ -4259,6 +4270,17 @@ Boolean Value 1 + + IMShowContentPanel + + Comment + Show Toolbar and Body Panels + Persist + 1 + Type + Boolean + Value + 1 IgnoreAllNotifications diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index 363713f2f4..590f41283b 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -281,6 +281,28 @@ Value 2 + NearbyChatIsNotTornOff + + Comment + saving torn-off state of the nearby chat between sessions + Persist + 1 + Type + Boolean + Value + 1 + + NearbyChatIsNotCollapsed + + Comment + Saving expanded/collapsed state of the nearby chat between sessions + Persist + 1 + Type + Boolean + Value + 0 + ShowFavoritesOnLogin Comment diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index ce063a9887..b513a52ff7 100755 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -193,7 +193,7 @@ static void on_avatar_name_cache_start_im(const LLUUID& agent_id, // static void LLAvatarActions::startIM(const LLUUID& id) { - if (id.isNull()) + if (id.isNull() || gAgent.getID() == id) return; LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_cache_start_im, _1, _2)); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index c4f63d9256..53926c1fef 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -58,7 +58,7 @@ #include "llworld.h" #include "lluiconstants.h" #include "llstring.h" - +#include "llurlaction.h" #include "llviewercontrol.h" static LLDefaultChildRegistry::Register r("chat_history"); @@ -156,6 +156,17 @@ public: LLFloaterSidePanelContainer::showPanel("people", "panel_people", LLSD().with("people_panel_tab_name", "blocked_panel").with("blocked_to_select", getAvatarId())); } + else if (level == "map") + { + std::string url = "secondlife://" + mObjectData["slurl"].asString(); + LLUrlAction::showLocationOnMap(url); + } + else if (level == "teleport") + { + std::string url = "secondlife://" + mObjectData["slurl"].asString(); + LLUrlAction::teleportToLocation(url); + } + } void onAvatarIconContextMenuItemClicked(const LLSD& userdata) @@ -820,6 +831,15 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL body_message_params.font.style = "ITALIC"; } + if(chat.mChatType == CHAT_TYPE_WHISPER) + { + body_message_params.font.style = "ITALIC"; + } + else if(chat.mChatType == CHAT_TYPE_SHOUT) + { + body_message_params.font.style = "BOLD"; + } + bool message_from_log = chat.mChatStyle == CHAT_STYLE_HISTORY; // We graying out chat history by graying out messages that contains full date in a time string if (message_from_log) diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 3dbb43c657..43c6b558bc 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -174,6 +174,7 @@ void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data) if("close all" == action) { LLNotificationWellWindow::getInstance()->closeAll(); + LLIMWellWindow::getInstance()->closeAll(); } } @@ -427,6 +428,8 @@ LLChicletPanel::~LLChicletPanel() void LLChicletPanel::onMessageCountChanged(const LLSD& data) { + // *TODO : we either suppress this method or return a value. Right now, it servers no purpose. + /* LLUUID session_id = data["session_id"].asUUID(); S32 unread = data["participant_unread"].asInteger(); @@ -435,6 +438,7 @@ void LLChicletPanel::onMessageCountChanged(const LLSD& data) { unread = 0; } + */ } void LLChicletPanel::objectChicletCallback(const LLSD& data) diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index 4be169e267..7883e4cb89 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -28,9 +28,11 @@ #include "llagent.h" #include "llavatarnamecache.h" #include "llconversationlog.h" +#include "lldiriterator.h" #include "llnotificationsutil.h" #include "lltrans.h" +#include #include "boost/lexical_cast.hpp" const int CONVERSATION_LIFETIME = 30; // lifetime of LLConversation is 30 days by spec @@ -192,14 +194,17 @@ LLConversationLog::LLConversationLog() : mAvatarNameCacheConnection(), mLoggingEnabled(false) { - LLControlVariable * keep_log_ctrlp = gSavedPerAccountSettings.getControl("KeepConversationLogTranscripts").get(); - S32 log_mode = keep_log_ctrlp->getValue(); - keep_log_ctrlp->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2)); - if (log_mode > 0) + if(gSavedPerAccountSettings.controlExists("KeepConversationLogTranscripts")) { - loadFromFile(getFileName()); + LLControlVariable * keep_log_ctrlp = gSavedPerAccountSettings.getControl("KeepConversationLogTranscripts").get(); + S32 log_mode = keep_log_ctrlp->getValue(); + keep_log_ctrlp->getSignal()->connect(boost::bind(&LLConversationLog::enableLogging, this, _2)); + if (log_mode > 0) + { + loadFromFile(getFileName()); - enableLogging(log_mode); + enableLogging(log_mode); + } } } @@ -380,6 +385,36 @@ void LLConversationLog::cache() } } +void LLConversationLog::getListOfBackupLogs(std::vector& list_of_backup_logs) +{ + // get Users log directory + std::string dirname = gDirUtilp->getPerAccountChatLogsDir(); + + // add final OS dependent delimiter + dirname += gDirUtilp->getDirDelimiter(); + + // create search pattern + std::string pattern = "conversation.log.backup*"; + + LLDirIterator iter(dirname, pattern); + std::string filename; + while (iter.next(filename)) + { + list_of_backup_logs.push_back(gDirUtilp->add(dirname, filename)); + } +} + +void LLConversationLog::deleteBackupLogs() +{ + std::vector backup_logs; + getListOfBackupLogs(backup_logs); + + BOOST_FOREACH(const std::string& fullpath, backup_logs) + { + LLFile::remove(fullpath); + } +} + bool LLConversationLog::moveLog(const std::string &originDirectory, const std::string &targetDirectory) { @@ -575,5 +610,6 @@ void LLConversationLog::onClearLogResponse(const LLSD& notification, const LLSD& mConversations.clear(); notifyObservers(); cache(); + deleteBackupLogs(); } } diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h index 58e698de25..265b1f0ef0 100644 --- a/indra/newview/llconversationlog.h +++ b/indra/newview/llconversationlog.h @@ -138,6 +138,8 @@ public: */ void cache(); bool moveLog(const std::string &originDirectory, const std::string &targetDirectory); + void getListOfBackupLogs(std::vector& list_of_backup_logs); + void deleteBackupLogs(); void onClearLog(); void onClearLogResponse(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp index 96b225b841..5ab108b39f 100644 --- a/indra/newview/llconversationloglist.cpp +++ b/indra/newview/llconversationloglist.cpp @@ -198,6 +198,8 @@ void LLConversationLogList::refresh() void LLConversationLogList::rebuildList() { + const LLConversation * selected_conversationp = getSelectedConversation(); + clear(); bool have_filter = !mNameFilter.empty(); @@ -214,7 +216,12 @@ void LLConversationLogList::rebuildList() addNewItem(&*iter); } - + + // try to restore selection of item + if (NULL != selected_conversationp) + { + selectItemByUUID(selected_conversationp->getSessionID()); + } bool logging_enabled = log_instance.getIsLoggingEnabled(); bool log_empty = log_instance.isLogEmpty(); @@ -238,8 +245,16 @@ void LLConversationLogList::rebuildList() void LLConversationLogList::onCustomAction(const LLSD& userdata) { + const LLConversation * selected_conversationp = getSelectedConversation(); + + if (NULL == selected_conversationp) + { + return; + } + const std::string command_name = userdata.asString(); - const LLUUID& selected_id = getSelectedConversation()->getParticipantID(); + const LLUUID& selected_conversation_participant_id = selected_conversationp->getParticipantID(); + const LLUUID& selected_conversation_session_id = selected_conversationp->getSessionID(); LLIMModel::LLIMSession::SType stype = getSelectedSessionType(); if ("im" == command_name) @@ -247,11 +262,11 @@ void LLConversationLogList::onCustomAction(const LLSD& userdata) switch (stype) { case LLIMModel::LLIMSession::P2P_SESSION: - LLAvatarActions::startIM(selected_id); + LLAvatarActions::startIM(selected_conversation_participant_id); break; case LLIMModel::LLIMSession::GROUP_SESSION: - LLGroupActions::startIM(getSelectedConversation()->getSessionID()); + LLGroupActions::startIM(selected_conversation_session_id); break; default: @@ -263,11 +278,11 @@ void LLConversationLogList::onCustomAction(const LLSD& userdata) switch (stype) { case LLIMModel::LLIMSession::P2P_SESSION: - LLAvatarActions::startCall(selected_id); + LLAvatarActions::startCall(selected_conversation_participant_id); break; case LLIMModel::LLIMSession::GROUP_SESSION: - LLGroupActions::startCall(getSelectedConversation()->getSessionID()); + LLGroupActions::startCall(selected_conversation_session_id); break; default: @@ -279,11 +294,11 @@ void LLConversationLogList::onCustomAction(const LLSD& userdata) switch (stype) { case LLIMModel::LLIMSession::P2P_SESSION: - LLAvatarActions::showProfile(selected_id); + LLAvatarActions::showProfile(selected_conversation_participant_id); break; case LLIMModel::LLIMSession::GROUP_SESSION: - LLGroupActions::show(getSelectedConversation()->getSessionID()); + LLGroupActions::show(selected_conversation_session_id); break; default: @@ -292,52 +307,53 @@ void LLConversationLogList::onCustomAction(const LLSD& userdata) } else if ("chat_history" == command_name) { - const LLUUID& session_id = getSelectedConversation()->getSessionID(); - LLFloaterReg::showInstance("preview_conversation", session_id, true); + LLFloaterReg::showInstance("preview_conversation", selected_conversation_session_id, true); } else if ("offer_teleport" == command_name) { - LLAvatarActions::offerTeleport(selected_id); + LLAvatarActions::offerTeleport(selected_conversation_participant_id); } else if("add_friend" == command_name) { - if (!LLAvatarActions::isFriend(selected_id)) + if (!LLAvatarActions::isFriend(selected_conversation_participant_id)) { - LLAvatarActions::requestFriendshipDialog(selected_id); + LLAvatarActions::requestFriendshipDialog(selected_conversation_participant_id); } } else if("remove_friend" == command_name) { - if (LLAvatarActions::isFriend(selected_id)) + if (LLAvatarActions::isFriend(selected_conversation_participant_id)) { - LLAvatarActions::removeFriendDialog(selected_id); + LLAvatarActions::removeFriendDialog(selected_conversation_participant_id); } } else if ("invite_to_group" == command_name) { - LLAvatarActions::inviteToGroup(selected_id); + LLAvatarActions::inviteToGroup(selected_conversation_participant_id); } else if ("show_on_map" == command_name) { - LLAvatarActions::showOnMap(selected_id); + LLAvatarActions::showOnMap(selected_conversation_participant_id); } else if ("share" == command_name) { - LLAvatarActions::share(selected_id); + LLAvatarActions::share(selected_conversation_participant_id); } else if ("pay" == command_name) { - LLAvatarActions::pay(selected_id); + LLAvatarActions::pay(selected_conversation_participant_id); } else if ("block" == command_name) { - LLAvatarActions::toggleBlock(selected_id); + LLAvatarActions::toggleBlock(selected_conversation_participant_id); } } bool LLConversationLogList::isActionEnabled(const LLSD& userdata) { - if (numSelected() != 1) + const LLConversation * selected_conversationp = getSelectedConversation(); + + if (NULL == selected_conversationp || numSelected() > 1) { return false; } @@ -345,7 +361,7 @@ bool LLConversationLogList::isActionEnabled(const LLSD& userdata) const std::string command_name = userdata.asString(); LLIMModel::LLIMSession::SType stype = getSelectedSessionType(); - const LLUUID& selected_id = getSelectedConversation()->getParticipantID(); + const LLUUID& selected_id = selected_conversationp->getParticipantID(); bool is_p2p = LLIMModel::LLIMSession::P2P_SESSION == stype; bool is_group = LLIMModel::LLIMSession::GROUP_SESSION == stype; @@ -374,7 +390,7 @@ bool LLConversationLogList::isActionEnabled(const LLSD& userdata) { return is_p2p && LLAvatarActions::canOfferTeleport(selected_id); } - else if ("can_show_on_map") + else if ("can_show_on_map" == command_name) { return is_p2p && ((LLAvatarTracker::instance().isBuddyOnline(selected_id) && is_agent_mappable(selected_id)) || gAgent.isGodlike()); } @@ -384,9 +400,16 @@ bool LLConversationLogList::isActionEnabled(const LLSD& userdata) bool LLConversationLogList::isActionChecked(const LLSD& userdata) { + const LLConversation * selected_conversationp = getSelectedConversation(); + + if (NULL == selected_conversationp) + { + return false; + } + const std::string command_name = userdata.asString(); - const LLUUID& selected_id = getSelectedConversation()->getParticipantID(); + const LLUUID& selected_id = selected_conversationp->getParticipantID(); bool is_p2p = LLIMModel::LLIMSession::P2P_SESSION == getSelectedSessionType(); if ("is_blocked" == command_name) diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 009fce0a92..c74ce24872 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -139,6 +139,8 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32 items.push_back(std::string("remove_friend")); items.push_back(std::string("invite_to_group")); items.push_back(std::string("separator_invite_to_group")); + if (static_cast(mParent)->getType() == CONV_SESSION_NEARBY) + items.push_back(std::string("zoom_in")); items.push_back(std::string("map")); items.push_back(std::string("share")); items.push_back(std::string("pay")); diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 74b348cd81..956abcd586 100755 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -104,6 +104,15 @@ LLConversationViewSession::~LLConversationViewSession() void LLConversationViewSession::setFlashState(bool flash_state) { + if (flash_state && !mFlashStateOn) + { + // flash chat toolbar button if scrolled out of sight (because flashing will not be visible) + if (mContainer->isScrolledOutOfSight(this)) + { + gToolBarView->flashCommand(LLCommandId("chat"), true); + } + } + mFlashStateOn = flash_state; mFlashStarted = false; mFlashTimer->stopFlashing(); @@ -115,12 +124,6 @@ void LLConversationViewSession::startFlashing() { mFlashStarted = true; mFlashTimer->startFlashing(); - - // flash chat toolbar button if scrolled out of sight (because flashing will not be visible) - if (mContainer->isScrolledOutOfSight(this)) - { - gToolBarView->flashCommand(LLCommandId("chat"), true); - } } } @@ -254,20 +257,38 @@ BOOL LLConversationViewSession::handleMouseDown( S32 x, S32 y, MASK mask ) //This node (conversation) was selected and a child (participant) was not if(result && getRoot()) { - if(getRoot()->getCurSelectedItem() == this) - { - LLConversationItem* item = dynamic_cast(getViewModelItem()); - LLUUID session_id = item? item->getUUID() : LLUUID(); - - LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance("im_container"); - im_container->flashConversationItemWidget(session_id,false); - im_container->selectConversationPair(session_id, false); - im_container->collapseMessagesPane(false); - } + selectConversationItem(); } + return result; } +BOOL LLConversationViewSession::handleRightMouseDown( S32 x, S32 y, MASK mask ) +{ + BOOL result = LLFolderViewFolder::handleRightMouseDown(x, y, mask); + + if(result) + { + selectConversationItem(); + } + + return result; +} + +void LLConversationViewSession::selectConversationItem() +{ + if(getRoot()->getCurSelectedItem() == this) + { + LLConversationItem* item = dynamic_cast(getViewModelItem()); + LLUUID session_id = item? item->getUUID() : LLUUID(); + + LLFloaterIMContainer *im_container = LLFloaterReg::getTypedInstance("im_container"); + im_container->flashConversationItemWidget(session_id,false); + im_container->selectConversationPair(session_id, false); + im_container->collapseMessagesPane(false); + } +} + // virtual S32 LLConversationViewSession::arrange(S32* width, S32* height) { diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index 76d3d079ea..3eb2e63792 100755 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -68,6 +68,7 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void draw(); /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); /*virtual*/ S32 arrange(S32* width, S32* height); @@ -90,6 +91,7 @@ private: void onCurrentVoiceSessionChanged(const LLUUID& session_id); void startFlashing(); + void selectConversationItem(); LLPanel* mItemPanel; LLPanel* mCallIconLayoutPanel; diff --git a/indra/newview/lldelayedgestureerror.cpp b/indra/newview/lldelayedgestureerror.cpp index 80e7c9f1b2..ef1b644ad4 100644 --- a/indra/newview/lldelayedgestureerror.cpp +++ b/indra/newview/lldelayedgestureerror.cpp @@ -113,9 +113,11 @@ bool LLDelayedGestureError::doDialog(const LLErrorEntry &ent, bool uuid_ok) } } - - LLNotificationsUtil::add(ent.mNotifyName, args); - + if(!LLApp::isQuitting()) + { + LLNotificationsUtil::add(ent.mNotifyName, args); + } + return true; } diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index 22f35752bd..82affcf068 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -33,6 +33,7 @@ #include "lldir.h" #include "llerror.h" #include "llfloaterreg.h" +#include "llimview.h" #include "llnotifications.h" #include "llnotificationhandler.h" #include "llnotificationstorage.h" @@ -131,6 +132,8 @@ void LLDoNotDisturbNotificationStorage::loadNotifications() { LLFastTimer _(FTM_LOAD_DND_NOTIFICATIONS); + LL_INFOS("LLDoNotDisturbNotificationStorage") << "start loading notifications" << LL_ENDL; + LLSD input; if (!readNotifications(input) ||input.isUndefined()) { @@ -145,6 +148,8 @@ void LLDoNotDisturbNotificationStorage::loadNotifications() LLNotifications& instance = LLNotifications::instance(); bool imToastExists = false; + bool group_ad_hoc_toast_exists = false; + S32 toastSessionType; bool offerExists = false; for (LLSD::array_const_iterator notification_it = data.beginArray(); @@ -158,7 +163,20 @@ void LLDoNotDisturbNotificationStorage::loadNotifications() if(notificationName == toastName) { - imToastExists = true; + toastSessionType = notification_params["payload"]["SESSION_TYPE"]; + if(toastSessionType == LLIMModel::LLIMSession::P2P_SESSION) + { + imToastExists = true; + } + //Don't add group/ad-hoc messages to the notification system because + //this means the group/ad-hoc session has to be re-created + else if(toastSessionType == LLIMModel::LLIMSession::GROUP_SESSION + || toastSessionType == LLIMModel::LLIMSession::ADHOC_SESSION) + { + //Just allows opening the conversation log for group/ad-hoc messages upon startup + group_ad_hoc_toast_exists = true; + continue; + } } else if(notificationName == offerName) { @@ -197,13 +215,20 @@ void LLDoNotDisturbNotificationStorage::loadNotifications() LLFloaterReg::showInstance("im_container"); } - if(imToastExists || offerExists) + if(group_ad_hoc_toast_exists) + { + LLFloaterReg::showInstance("conversation"); + } + + if(imToastExists || group_ad_hoc_toast_exists || offerExists) { make_ui_sound_deferred("UISndNewIncomingIMSession"); } //writes out empty .xml file (since LLCommunicationChannel::mHistory is empty) saveNotifications(); + + LL_INFOS("LLDoNotDisturbNotificationStorage") << "finished loading notifications" << LL_ENDL; } void LLDoNotDisturbNotificationStorage::updateNotifications() diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 413707baae..7296ec3ced 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -53,6 +53,7 @@ #include "llcallbacklist.h" #include "llworld.h" #include "llsdserialize.h" +#include "llviewerobjectlist.h" // // LLFloaterIMContainer @@ -62,8 +63,7 @@ LLFloaterIMContainer::LLFloaterIMContainer(const LLSD& seed, const Params& param mExpandCollapseBtn(NULL), mConversationsRoot(NULL), mConversationsEventStream("ConversationsEvents"), - mInitialized(false), - mIsFirstLaunch(false) + mInitialized(false) { mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLFloaterIMContainer::isActionChecked, this, _2)); mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLFloaterIMContainer::onCustomAction, this, _2)); @@ -114,6 +114,7 @@ void LLFloaterIMContainer::sessionAdded(const LLUUID& session_id, const std::str void LLFloaterIMContainer::sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) { selectConversationPair(session_id, true); + collapseMessagesPane(false); } void LLFloaterIMContainer::sessionVoiceOrIMStarted(const LLUUID& session_id) @@ -225,10 +226,11 @@ BOOL LLFloaterIMContainer::postBuild() childSetAction("add_btn", boost::bind(&LLFloaterIMContainer::onAddButtonClicked, this)); collapseMessagesPane(gSavedPerAccountSettings.getBOOL("ConversationsMessagePaneCollapsed")); - collapseConversationsPane(gSavedPerAccountSettings.getBOOL("ConversationsListPaneCollapsed")); + collapseConversationsPane(gSavedPerAccountSettings.getBOOL("ConversationsListPaneCollapsed"), false); LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLFloaterIMSessionTab::processChatHistoryStyleUpdate, false)); mMicroChangedSignal = LLVoiceClient::getInstance()->MicroChangedCallback(boost::bind(&LLFloaterIMContainer::updateSpeakBtnState, this)); - if (! mMessagesPane->isCollapsed()) + + if (! mMessagesPane->isCollapsed() && ! mConversationsPane->isCollapsed()) { S32 conversations_panel_width = gSavedPerAccountSettings.getS32("ConversationsListPaneWidth"); LLRect conversations_panel_rect = mConversationsPane->getRect(); @@ -243,7 +245,6 @@ BOOL LLFloaterIMContainer::postBuild() mGeneralTitle = getTitle(); mInitialized = true; - mIsFirstLaunch = true; // Add callbacks: // We'll take care of view updates on idle @@ -278,12 +279,6 @@ void LLFloaterIMContainer::addFloater(LLFloater* floaterp, LLUUID session_id = floaterp->getKey(); - // Make sure the message panel is open when adding a floater or it stays mysteriously hidden - if (!mIsFirstLaunch) - { - collapseMessagesPane(false); - } - // Add the floater LLMultiFloater::addFloater(floaterp, select_added_floater, insertion_point); @@ -631,6 +626,12 @@ void LLFloaterIMContainer::setVisible(BOOL visible) LLMultiFloater::setVisible(visible); } +void LLFloaterIMContainer::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key) +{ + LLMultiFloater::setVisibleAndFrontmost(take_focus, key); + selectConversationPair(getSelectedSession(), false, take_focus); +} + void LLFloaterIMContainer::updateResizeLimits() { LLMultiFloater::updateResizeLimits(); @@ -644,8 +645,6 @@ void LLFloaterIMContainer::collapseMessagesPane(bool collapse) return; } - mIsFirstLaunch = false; - // Save current width of panels before collapsing/expanding right pane. S32 conv_pane_width = mConversationsPane->getRect().getWidth(); S32 msg_pane_width = mMessagesPane->getRect().getWidth(); @@ -667,7 +666,7 @@ void LLFloaterIMContainer::collapseMessagesPane(bool collapse) // Make sure layout is updated before resizing conversation pane. mConversationsStack->updateLayout(); - updateState(collapse, gSavedPerAccountSettings.getS32("ConversationsMessagePaneWidth")); + reshapeFloaterAndSetResizeLimits(collapse, gSavedPerAccountSettings.getS32("ConversationsMessagePaneWidth")); if (!collapse) { @@ -676,7 +675,7 @@ void LLFloaterIMContainer::collapseMessagesPane(bool collapse) } } -void LLFloaterIMContainer::collapseConversationsPane(bool collapse) +void LLFloaterIMContainer::collapseConversationsPane(bool collapse, bool save_is_allowed /*=true*/) { if (mConversationsPane->isCollapsed() == collapse) { @@ -690,7 +689,7 @@ void LLFloaterIMContainer::collapseConversationsPane(bool collapse) // Save current width of Conversation panel before collapsing/expanding right pane. S32 conv_pane_width = mConversationsPane->getRect().getWidth(); - if (collapse) + if (collapse && save_is_allowed) { // Save the conversations pane width before collapsing it. gSavedPerAccountSettings.setS32("ConversationsListPaneWidth", conv_pane_width); @@ -700,10 +699,18 @@ void LLFloaterIMContainer::collapseConversationsPane(bool collapse) } mConversationsStack->collapsePanel(mConversationsPane, collapse); + if (!collapse) + { + // Make sure layout is updated before resizing conversation pane. + mConversationsStack->updateLayout(); + // Restore conversation's pane previous width. + mConversationsPane->setTargetDim(gSavedPerAccountSettings.getS32("ConversationsListPaneWidth")); + } - S32 delta_width = gSavedPerAccountSettings.getS32("ConversationsListPaneWidth") - mConversationsPane->getMinDim(); + S32 delta_width = + gSavedPerAccountSettings.getS32("ConversationsListPaneWidth") - mConversationsPane->getMinDim(); - updateState(collapse, delta_width); + reshapeFloaterAndSetResizeLimits(collapse, delta_width); for (conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin(); widget_it != mConversationsWidgets.end(); ++widget_it) @@ -723,21 +730,20 @@ void LLFloaterIMContainer::collapseConversationsPane(bool collapse) } } -void LLFloaterIMContainer::updateState(bool collapse, S32 delta_width) +void LLFloaterIMContainer::reshapeFloaterAndSetResizeLimits(bool collapse, S32 delta_width) { LLRect floater_rect = getRect(); floater_rect.mRight += ((collapse ? -1 : 1) * delta_width); // Set by_user = true so that reshaped rect is saved in user_settings. setShape(floater_rect, true); - updateResizeLimits(); - bool is_left_pane_expanded = !mConversationsPane->isCollapsed(); - bool is_right_pane_expanded = !mMessagesPane->isCollapsed(); + bool at_least_one_panel_is_expanded = + ! (mConversationsPane->isCollapsed() && mMessagesPane->isCollapsed()); - setCanResize(is_left_pane_expanded || is_right_pane_expanded); - setCanMinimize(is_left_pane_expanded || is_right_pane_expanded); + setCanResize(at_least_one_panel_is_expanded); + setCanMinimize(at_least_one_panel_is_expanded); assignResizeLimits(); @@ -758,21 +764,17 @@ void LLFloaterIMContainer::assignResizeLimits() // between the panels are merged into one S32 number_of_visible_borders = llmin((is_conv_pane_expanded? 2 : 0) + (is_msg_pane_expanded? 2 : 0), 3); S32 summary_width_of_visible_borders = number_of_visible_borders * LLPANEL_BORDER_WIDTH; - S32 conv_pane_current_width = is_msg_pane_expanded - ? (is_conv_pane_expanded? mConversationsPane->getRect().getWidth() : mConversationsPane->getMinDim()) - : (is_conv_pane_expanded? mConversationsPane->getExpandedMinDim() : mConversationsPane->getMinDim()); + S32 conv_pane_target_width = is_conv_pane_expanded? + (is_msg_pane_expanded? + mConversationsPane->getRect().getWidth() + : mConversationsPane->getExpandedMinDim()) + : mConversationsPane->getMinDim(); S32 msg_pane_min_width = is_msg_pane_expanded ? mMessagesPane->getExpandedMinDim() : 0; - S32 new_min_width = conv_pane_current_width + msg_pane_min_width + summary_width_of_visible_borders; - - if (is_conv_pane_expanded) - { - // Save the conversations pane width. - gSavedPerAccountSettings.setS32( - "ConversationsListPaneWidth", - mConversationsPane->getRect().getWidth()); - } + S32 new_min_width = conv_pane_target_width + msg_pane_min_width + summary_width_of_visible_borders; setResizeLimits(new_min_width, getMinHeight()); + + mConversationsStack->updateLayout(); } void LLFloaterIMContainer::onAddButtonClicked() @@ -1031,6 +1033,10 @@ void LLFloaterIMContainer::doToParticipants(const std::string& command, uuid_vec { LLAvatarActions::inviteToGroup(userID); } + else if ("zoom_in" == command) + { + handle_zoom_to_object(userID); + } else if ("map" == command) { LLAvatarActions::showOnMap(userID); @@ -1252,6 +1258,10 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v { return LLAvatarActions::canCall(); } + else if ("can_zoom_in" == item) + { + return is_single_select && gObjectList.findObject(single_id); + } else if ("can_show_on_map" == item) { return (is_single_select ? (LLAvatarTracker::instance().isBuddyOnline(single_id) && is_agent_mappable(single_id)) || gAgent.isGodlike() : false); @@ -1325,6 +1335,12 @@ void LLFloaterIMContainer::showConversation(const LLUUID& session_id) { setVisibleAndFrontmost(false); selectConversationPair(session_id, true); + + LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(session_id); + if (session_floater) + { + session_floater->restoreFloater(); + } } void LLFloaterIMContainer::clearAllFlashStates() @@ -1400,6 +1416,10 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool // Switch to the conversation floater that is being selected selectFloater(session_floater); } + else + { + showStub(true); + } } // Set the focus on the selected floater @@ -1410,7 +1430,7 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool session_floater->setMinimized(is_minimized); } } - + flashConversationItemWidget(session_id,false); return handled; } @@ -1878,6 +1898,9 @@ bool LLFloaterIMContainer::isScrolledOutOfSight(LLConversationViewSession* conve { llassert(conversation_item_widget != NULL); + // make sure the widget is actually in the right spot first + mConversationsRoot->arrange(NULL, NULL); + // check whether the widget is in the visible portion of the scroll container LLRect widget_rect; conversation_item_widget->localRectToOtherView(conversation_item_widget->getLocalRect(), &widget_rect, mConversationsRoot); @@ -1905,7 +1928,19 @@ BOOL LLFloaterIMContainer::handleKeyHere(KEY key, MASK mask ) return TRUE; } -bool LLFloaterIMContainer::selectNextorPreviousConversation(bool select_next) +bool LLFloaterIMContainer::selectAdjacentConversation(bool focus_selected) +{ + bool selectedAdjacentConversation = selectNextorPreviousConversation(true, focus_selected); + + if(!selectedAdjacentConversation) + { + selectedAdjacentConversation = selectNextorPreviousConversation(false, focus_selected); + } + + return selectedAdjacentConversation; +} + +bool LLFloaterIMContainer::selectNextorPreviousConversation(bool select_next, bool focus_selected) { if (mConversationsWidgets.size() > 1) { @@ -1926,12 +1961,7 @@ bool LLFloaterIMContainer::selectNextorPreviousConversation(bool select_next) LLConversationItem* vmi = dynamic_cast(new_selection->getViewModelItem()); if (vmi) { - selectConversationPair(vmi->getUUID(), true); - LLFloater* floaterp = get_ptr_in_map(mSessions, getSelectedSession()); - if(floaterp && !floaterp->isTornOff()) - { - setFocus(TRUE); - } + selectConversationPair(vmi->getUUID(), true, focus_selected); return true; } } @@ -1942,10 +1972,13 @@ bool LLFloaterIMContainer::selectNextorPreviousConversation(bool select_next) void LLFloaterIMContainer::expandConversation() { - LLConversationViewSession* widget = dynamic_cast(get_ptr_in_map(mConversationsWidgets,getSelectedSession())); - if (widget) + if(!mConversationsPane->isCollapsed()) { - widget->setOpen(!widget->isOpen()); + LLConversationViewSession* widget = dynamic_cast(get_ptr_in_map(mConversationsWidgets,getSelectedSession())); + if (widget) + { + widget->setOpen(!widget->isOpen()); + } } } @@ -1955,11 +1988,6 @@ void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/) // Most of the time the user will never see this state. setMinimized(FALSE); - // Save the conversations pane width. - gSavedPerAccountSettings.setS32( - "ConversationsListPaneWidth", - mConversationsPane->getRect().getWidth()); - LLFloater::closeFloater(app_quitting); } diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index c84d4978ec..52b672241f 100644 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -60,6 +60,7 @@ public: /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ void draw(); /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); /*virtual*/ void updateResizeLimits(); void onCloseFloater(LLUUID& id); @@ -72,7 +73,8 @@ public: void selectNextConversationByID(const LLUUID& session_id); BOOL selectConversationPair(const LLUUID& session_id, bool select_widget, bool focus_floater = true); void clearAllFlashStates(); - bool selectNextorPreviousConversation(bool select_next); + bool selectAdjacentConversation(bool focus_selected); + bool selectNextorPreviousConversation(bool select_next, bool focus_selected = true); void expandConversation(); /*virtual*/ void tabClose(); @@ -128,9 +130,9 @@ private: void processParticipantsStyleUpdate(); void onSpeakButtonClicked(); - void collapseConversationsPane(bool collapse); + void collapseConversationsPane(bool collapse, bool save_is_allowed=true); - void updateState(bool collapse, S32 delta_width); + void reshapeFloaterAndSetResizeLimits(bool collapse, S32 delta_width); void onAddButtonClicked(); void onAvatarPicked(const uuid_vec_t& ids); @@ -173,7 +175,6 @@ private: LLLayoutStack* mConversationsStack; bool mInitialized; - bool mIsFirstLaunch; LLUUID mSelectedSession; std::string mGeneralTitle; diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index dfaf4bbdd6..d86e1b3fd7 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -257,14 +257,25 @@ void LLFloaterIMNearbyChat::setVisible(BOOL visible) } } + +void LLFloaterIMNearbyChat::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key) +{ + LLFloaterIMSessionTab::setVisibleAndFrontmost(take_focus, key); + + if(!isTornOff() && matchesKey(key)) + { + LLFloaterIMContainer::getInstance()->selectConversationPair(mSessionID, true, false); + } +} + // virtual void LLFloaterIMNearbyChat::onTearOffClicked() { LLFloaterIMSessionTab::onTearOffClicked(); // see CHUI-170: Save torn-off state of the nearby chat between sessions - BOOL in_the_multifloater = !isTornOff(); - gSavedSettings.setBOOL("NearbyChatIsNotTornOff", in_the_multifloater); + BOOL in_the_multifloater = (BOOL)getHost(); + gSavedPerAccountSettings.setBOOL("NearbyChatIsNotTornOff", in_the_multifloater); } @@ -272,6 +283,11 @@ void LLFloaterIMNearbyChat::onTearOffClicked() void LLFloaterIMNearbyChat::onOpen(const LLSD& key) { LLFloaterIMSessionTab::onOpen(key); + if(!isMessagePaneExpanded()) + { + restoreFloater(); + onCollapseToLine(this); + } showTranslationCheckbox(LLTranslate::isTranslationConfigured()); } @@ -279,6 +295,7 @@ void LLFloaterIMNearbyChat::onOpen(const LLSD& key) void LLFloaterIMNearbyChat::onClose(bool app_quitting) { // Override LLFloaterIMSessionTab::onClose() so that Nearby Chat is not removed from the conversation floater + LLFloaterIMSessionTab::restoreFloater(); onClickCloseBtn(); } @@ -286,8 +303,10 @@ void LLFloaterIMNearbyChat::onClose(bool app_quitting) void LLFloaterIMNearbyChat::onClickCloseBtn() { if (!isTornOff()) + { return; - onTearOffClicked(); + } + LLFloaterIMSessionTab::onTearOffClicked(); LLFloaterIMContainer *im_box = LLFloaterIMContainer::findInstance(); if (im_box) @@ -308,11 +327,8 @@ void LLFloaterIMNearbyChat::onChatFontChange(LLFontGL* fontp) void LLFloaterIMNearbyChat::show() { - if (isChatMultiTab()) - { openFloater(getKey()); } -} bool LLFloaterIMNearbyChat::isChatVisible() const { @@ -323,7 +339,7 @@ bool LLFloaterIMNearbyChat::isChatVisible() const if (im_box != NULL) { isVisible = - isChatMultiTab() && gSavedSettings.getBOOL("NearbyChatIsNotTornOff")? + isChatMultiTab() && gSavedPerAccountSettings.getBOOL("NearbyChatIsNotTornOff")? im_box->getVisible() && !im_box->isMinimized() : getVisible() && !isMinimized(); } @@ -334,6 +350,11 @@ bool LLFloaterIMNearbyChat::isChatVisible() const void LLFloaterIMNearbyChat::showHistory() { openFloater(); + if(!isMessagePaneExpanded()) + { + restoreFloater(); + setFocus(true); + } setResizeLimits(getMinWidth(), EXPANDED_MIN_HEIGHT); } @@ -406,6 +427,12 @@ BOOL LLFloaterIMNearbyChat::matchChatTypeTrigger(const std::string& in_str, std: void LLFloaterIMNearbyChat::onChatBoxKeystroke() { + LLFloaterIMContainer* im_box = LLFloaterIMContainer::findInstance(); + if (im_box) + { + im_box->flashConversationItemWidget(mSessionID,false); + } + LLFirstUse::otherAvatarChatFirst(false); LLWString raw_text = mInputEditor->getWText(); @@ -455,11 +482,14 @@ void LLFloaterIMNearbyChat::onChatBoxKeystroke() if (LLGestureMgr::instance().matchPrefix(utf8_trigger, &utf8_out_str)) { std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size()); - mInputEditor->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part + if (!rest_of_match.empty()) + { + mInputEditor->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part - // Select to end of line, starting from the character - // after the last one the user typed. - mInputEditor->selectNext(rest_of_match, false); + // Select to end of line, starting from the character + // after the last one the user typed. + mInputEditor->selectNext(rest_of_match, false); + } } else if (matchChatTypeTrigger(utf8_trigger, &utf8_out_str)) { @@ -714,10 +744,16 @@ void LLFloaterIMNearbyChat::startChat(const char* line) LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance("nearby_chat"); if (nearby_chat) { + if(!nearby_chat->isTornOff()) + { + LLFloaterIMContainer::getInstance()->selectConversation(LLUUID(NULL)); + } + if(nearby_chat->isMinimized()) + { + nearby_chat->setMinimized(false); + } nearby_chat->show(); - nearby_chat->setVisible(TRUE); nearby_chat->setFocus(TRUE); - nearby_chat->mInputEditor->setFocus(TRUE); if (line) { diff --git a/indra/newview/llfloaterimnearbychat.h b/indra/newview/llfloaterimnearbychat.h index 4ad37eb0c7..05b48cccb0 100644 --- a/indra/newview/llfloaterimnearbychat.h +++ b/indra/newview/llfloaterimnearbychat.h @@ -54,6 +54,7 @@ public: /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ void onClose(bool app_quitting); /*virtual*/ void setVisible(BOOL visible); + /*virtual*/ void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); /*virtual*/ void closeHostedFloater(); void loadHistory(); diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 8870d54cd2..0824b26406 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -559,12 +559,12 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance("im_container"); - if( nearby_chat->hasFocus() - || im_box->hasFocus() - || ( chat_msg.mSourceType == CHAT_SOURCE_AGENT + if(( ( chat_msg.mSourceType == CHAT_SOURCE_AGENT && gSavedSettings.getBOOL("UseChatBubbles") ) || mChannel.isDead() - || !mChannel.get()->getShowToasts() ) // to prevent toasts in Do Not Disturb mode + || !mChannel.get()->getShowToasts() ) + && nearby_chat->isMessagePaneExpanded()) + // to prevent toasts in Do Not Disturb mode return;//no need in toast if chat is visible or if bubble chat is enabled // arrange a channel on a screen @@ -604,17 +604,16 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, toast_msg = chat_msg.mText; } - //Don't show nearby toast, if conversation is visible but not focused - LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(LLUUID()); - if (session_floater - && session_floater->isInVisibleChain() && !session_floater->isMinimized() - && !(session_floater->getHost() && session_floater->getHost()->isMinimized())) + //Don't show nearby toast, if conversation is visible and selected + if (im_box->getSelectedSession().isNull() && + ((LLFloater::isVisible(im_box) && !im_box->isMinimized() && im_box->isFrontmost()) + || (LLFloater::isVisible(nearby_chat) && !nearby_chat->isMinimized() && nearby_chat->isFrontmost()))) { return; } //Will show toast when chat preference is set - if(gSavedSettings.getString("NotificationNearbyChatOptions") == "toast") + if((gSavedSettings.getString("NotificationNearbyChatOptions") == "toast") || !nearby_chat->isMessagePaneExpanded()) { // Add a nearby chat toast. LLUUID id; diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index 50b2ed8c51..6d5145f205 100644 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -618,7 +618,9 @@ void LLFloaterIMSession::onClose(bool app_quitting) // Last change: // EXT-3516 X Button should end IM session, _ button should hide gIMMgr->leaveSession(mSessionID); - + // *TODO: Study why we need to restore the floater before we close it. + // Might be because we want to save some state data in some clean open state. + LLFloaterIMSessionTab::restoreFloater(); // Clean up the conversation *after* the session has been ended LLFloaterIMSessionTab::onClose(app_quitting); } @@ -892,6 +894,11 @@ void LLFloaterIMSession::onInputEditorFocusLost(LLFocusableElement* caller, void void LLFloaterIMSession::onInputEditorKeystroke(LLTextEditor* caller, void* userdata) { LLFloaterIMSession* self = (LLFloaterIMSession*)userdata; + LLFloaterIMContainer* im_box = LLFloaterIMContainer::findInstance(); + if (im_box) + { + im_box->flashConversationItemWidget(self->mSessionID,false); + } std::string text = self->mInputEditor->getText(); // Deleting all text counts as stopping typing. diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index d3fcfbbc56..5083331167 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -30,6 +30,7 @@ #include "llfloaterimsessiontab.h" #include "llagent.h" +#include "llagentcamera.h" #include "llavataractions.h" #include "llchatentry.h" #include "llchathistory.h" @@ -57,10 +58,12 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id) , mSpeakingIndicator(NULL) , mChatHistory(NULL) , mInputEditor(NULL) - , mInputEditorTopPad(0) + , mInputEditorPad(0) , mRefreshTimer(new LLTimer()) , mIsHostAttached(false) , mHasVisibleBeenInitialized(false) + , mIsParticipantListExpanded(true) + , mChatLayoutPanel(NULL) { setAutoFocus(FALSE); mSession = LLIMModel::getInstance()->findIMSession(mSessionID); @@ -124,8 +127,18 @@ void LLFloaterIMSessionTab::setVisible(BOOL visible) if(visible && !mHasVisibleBeenInitialized) { mHasVisibleBeenInitialized = true; - LLFloaterReg::getTypedInstance("im_container")->setVisible(true); + if(!gAgentCamera.cameraMouselook()) + { + LLFloaterReg::getTypedInstance("im_container")->setVisible(true); + } LLFloaterIMSessionTab::addToHost(mSessionID); + LLFloaterIMSessionTab* conversp = LLFloaterIMSessionTab::getConversation(mSessionID); + + if (conversp && conversp->isNearbyChat() && gSavedPerAccountSettings.getBOOL("NearbyChatIsNotCollapsed")) + { + onCollapseToLine(this); + } + mInputButtonPanel->setVisible(isTornOff()); } LLTransientDockableFloater::setVisible(visible); @@ -169,7 +182,7 @@ void LLFloaterIMSessionTab::addToHost(const LLUUID& session_id) conversp->setHostAttached(true); if (!conversp->isNearbyChat() - || gSavedSettings.getBOOL("NearbyChatIsNotTornOff")) + || gSavedPerAccountSettings.getBOOL("NearbyChatIsNotTornOff")) { floater_container->addFloater(conversp, false, LLTabContainer::RIGHT_OF_CURRENT); } @@ -180,6 +193,7 @@ void LLFloaterIMSessionTab::addToHost(const LLUUID& session_id) // LLFloater::mLastHostHandle = floater_container (a "future" host) conversp->setHost(floater_container); conversp->setHost(NULL); + conversp->forceReshape(); } // Added floaters share some state (like sort order) with their host @@ -188,23 +202,51 @@ void LLFloaterIMSessionTab::addToHost(const LLUUID& session_id) } } +void LLFloaterIMSessionTab::assignResizeLimits() +{ + bool is_participants_pane_collapsed = mParticipantListPanel->isCollapsed(); + + // disable a layoutstack's functionality when participant list panel is collapsed + mRightPartPanel->setIgnoreReshape(is_participants_pane_collapsed); + + S32 participants_pane_target_width = is_participants_pane_collapsed? + 0 : (mParticipantListPanel->getRect().getWidth() + LLPANEL_BORDER_WIDTH); + + S32 new_min_width = participants_pane_target_width + mRightPartPanel->getExpandedMinDim() + mFloaterExtraWidth; + + setResizeLimits(new_min_width, getMinHeight()); + + this->mParticipantListAndHistoryStack->updateLayout(); +} + BOOL LLFloaterIMSessionTab::postBuild() { BOOL result; + mBodyStack = getChild("main_stack"); + mParticipantListAndHistoryStack = getChild("im_panels"); + mCloseBtn = getChild("close_btn"); mCloseBtn->setCommitCallback(boost::bind(&LLFloater::onClickClose, this)); mExpandCollapseBtn = getChild("expand_collapse_btn"); mExpandCollapseBtn->setClickedCallback(boost::bind(&LLFloaterIMSessionTab::onSlide, this)); + mExpandCollapseLineBtn = getChild("minz_btn"); + mExpandCollapseLineBtn->setClickedCallback(boost::bind(&LLFloaterIMSessionTab::onCollapseToLine, this)); + mTearOffBtn = getChild("tear_off_btn"); mTearOffBtn->setCommitCallback(boost::bind(&LLFloaterIMSessionTab::onTearOffClicked, this)); mGearBtn = getChild("gear_btn"); mParticipantListPanel = getChild("speakers_list_panel"); - + mRightPartPanel = getChild("right_part_holder"); + + mToolbarPanel = getChild("toolbar_panel"); + mContentPanel = getChild("body_panel"); + mInputButtonPanel = getChild("input_button_layout_panel"); + mInputButtonPanel->setVisible(false); // Add a scroller for the folder (participant) view LLRect scroller_view_rect = mParticipantListPanel->getRect(); scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); @@ -221,17 +263,20 @@ BOOL LLFloaterIMSessionTab::postBuild() mChatHistory = getChild("chat_history"); mInputEditor = getChild("chat_editor"); - mInputEditor->setTextExpandedCallback(boost::bind(&LLFloaterIMSessionTab::reshapeChatHistory, this)); + + mChatLayoutPanel = getChild("chat_layout_panel"); + + mInputEditor->setTextExpandedCallback(boost::bind(&LLFloaterIMSessionTab::reshapeChatLayoutPanel, this)); mInputEditor->setCommitOnFocusLost( FALSE ); mInputEditor->setPassDelete(TRUE); mInputEditor->setFont(LLViewerChat::getChatFont()); - mInputEditorTopPad = mChatHistory->getRect().mBottom - mInputEditor->getRect().mTop; + mInputEditorPad = mChatLayoutPanel->getRect().getHeight() - mInputEditor->getRect().getHeight(); setOpenPositioning(LLFloaterEnums::POSITIONING_RELATIVE); mSaveRect = isNearbyChat() - && !gSavedSettings.getBOOL("NearbyChatIsNotTornOff"); + && !gSavedPerAccountSettings.getBOOL("NearbyChatIsNotTornOff"); initRectControl(); if (isChatMultiTab()) @@ -253,6 +298,7 @@ BOOL LLFloaterIMSessionTab::postBuild() p.root = NULL; p.use_ellipses = true; p.options_menu = "menu_conversation.xml"; + p.name = "root"; mConversationsRoot = LLUICtrlFactory::create(p); mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); // Attach that root to the scroller @@ -261,6 +307,8 @@ BOOL LLFloaterIMSessionTab::postBuild() mConversationsRoot->setFollowsAll(); mConversationsRoot->addChild(mConversationsRoot->mStatusTextBox); + setMessagePaneExpanded(true); + buildConversationViewParticipant(); refreshConversation(); @@ -268,6 +316,21 @@ BOOL LLFloaterIMSessionTab::postBuild() mRefreshTimer->setTimerExpirySec(0); mRefreshTimer->start(); initBtns(); + + if (mIsParticipantListExpanded != (bool)gSavedSettings.getBOOL("IMShowControlPanel")) + { + LLFloaterIMSessionTab::onSlide(this); + } + + // The resize limits for LLFloaterIMSessionTab should be updated, based on current values of width of conversation and message panels + mParticipantListPanel->getResizeBar()->setResizeListener(boost::bind(&LLFloaterIMSessionTab::assignResizeLimits, this)); + mFloaterExtraWidth = + getRect().getWidth() + - mParticipantListAndHistoryStack->getRect().getWidth() + - (mParticipantListPanel->isCollapsed()? 0 : LLPANEL_BORDER_WIDTH); + + assignResizeLimits(); + return result; } @@ -299,7 +362,7 @@ void LLFloaterIMSessionTab::draw() // Restart the refresh timer mRefreshTimer->setTimerExpirySec(REFRESH_INTERVAL); } - + LLTransientDockableFloater::draw(); } @@ -324,13 +387,6 @@ void LLFloaterIMSessionTab::onFocusReceived() } LLTransientDockableFloater::onFocusReceived(); - - LLFloaterIMContainer* container = LLFloaterReg::findTypedInstance("im_container"); - if (container) - { - container->selectConversationPair(mSessionID, true); - container->showStub(! getHost()); - } } void LLFloaterIMSessionTab::onFocusLost() @@ -644,14 +700,16 @@ void LLFloaterIMSessionTab::updateHeaderAndToolbar() // Participant list should be visible only in torn off floaters. bool is_participant_list_visible = !is_not_torn_off - && gSavedSettings.getBOOL("IMShowControlPanel") + && mIsParticipantListExpanded && !mIsP2PChat; - mParticipantListPanel->setVisible(is_participant_list_visible); + mParticipantListAndHistoryStack->collapsePanel(mParticipantListPanel, !is_participant_list_visible); + mParticipantListPanel->setVisible(is_participant_list_visible); // Display collapse image (<<) if the floater is hosted // or if it is torn off but has an open control panel. bool is_expanded = is_not_torn_off || is_participant_list_visible; + mExpandCollapseBtn->setImageOverlay(getString(is_expanded ? "collapse_icon" : "expand_icon")); mExpandCollapseBtn->setToolTip( is_not_torn_off? @@ -672,6 +730,7 @@ void LLFloaterIMSessionTab::updateHeaderAndToolbar() mTearOffBtn->setImageOverlay(getString(is_not_torn_off? "tear_off_icon" : "return_icon")); mTearOffBtn->setToolTip(getString(is_not_torn_off? "tooltip_to_separate_window" : "tooltip_to_main_window")); + mCloseBtn->setVisible(is_not_torn_off && !mIsNearbyChat); enableDisableCallBtn(); @@ -688,15 +747,11 @@ void LLFloaterIMSessionTab::forceReshape() } -void LLFloaterIMSessionTab::reshapeChatHistory() +void LLFloaterIMSessionTab::reshapeChatLayoutPanel() { - LLRect chat_rect = mChatHistory->getRect(); + LLRect chat_layout_panel_rect = mChatLayoutPanel->getRect(); LLRect input_rect = mInputEditor->getRect(); - - int delta_height = chat_rect.mBottom - (input_rect.mTop + mInputEditorTopPad); - - chat_rect.setLeftTopAndSize(chat_rect.mLeft, chat_rect.mTop, chat_rect.getWidth(), chat_rect.getHeight() + delta_height); - mChatHistory->setShape(chat_rect); + mChatLayoutPanel->reshape(chat_layout_panel_rect.getWidth(), input_rect.getHeight() + mInputEditorPad, FALSE); } void LLFloaterIMSessionTab::showTranslationCheckbox(BOOL show) @@ -771,16 +826,77 @@ void LLFloaterIMSessionTab::onSlide(LLFloaterIMSessionTab* self) { if (!self->mIsP2PChat) { - bool expand = !self->mParticipantListPanel->getVisible(); + // The state must toggle the collapsed state of the panel + bool should_be_expanded = self->mParticipantListPanel->isCollapsed(); - // Expand/collapse the IM control panel - self->mParticipantListPanel->setVisible(expand); - - gSavedSettings.setBOOL("IMShowControlPanel", expand); - - self->mExpandCollapseBtn->setImageOverlay(self->getString(expand ? "collapse_icon" : "expand_icon")); + // Update the expand/collapse flag of the participant list panel and save it + gSavedSettings.setBOOL("IMShowControlPanel", should_be_expanded); + self->mIsParticipantListExpanded = should_be_expanded; + + // Refresh for immediate feedback + self->refreshConversation(); } } + + self->assignResizeLimits(); +} + +void LLFloaterIMSessionTab::onCollapseToLine(LLFloaterIMSessionTab* self) +{ + LLFloaterIMContainer* host_floater = dynamic_cast(self->getHost()); + if (!host_floater) + { + bool expand = self->isMessagePaneExpanded(); + self->mExpandCollapseLineBtn->setImageOverlay(self->getString(expand ? "collapseline_icon" : "expandline_icon")); + self->mContentPanel->setVisible(!expand); + self->mToolbarPanel->setVisible(!expand); + self->reshapeFloater(expand); + self->setMessagePaneExpanded(!expand); + } +} + +void LLFloaterIMSessionTab::reshapeFloater(bool collapse) +{ + LLRect floater_rect = getRect(); + + if(collapse) + { + mFloaterHeight = floater_rect.getHeight(); + S32 height = mContentPanel->getRect().getHeight() + mToolbarPanel->getRect().getHeight(); + floater_rect.mTop -= height; + enableResizeCtrls(true, true, false); + } + else + { + floater_rect.mTop = floater_rect.mBottom + mFloaterHeight; + enableResizeCtrls(true, true, true); + + } + saveCollapsedState(); + setShape(floater_rect, true); + mBodyStack->updateLayout(); + +} + +void LLFloaterIMSessionTab::restoreFloater() +{ + if(!isMessagePaneExpanded()) + { + if(isMinimized()) + { + setMinimized(false); + } + mContentPanel->setVisible(true); + mToolbarPanel->setVisible(true); + LLRect floater_rect = getRect(); + floater_rect.mTop = floater_rect.mBottom + mFloaterHeight; + setShape(floater_rect, true); + mBodyStack->updateLayout(); + mExpandCollapseLineBtn->setImageOverlay(getString("expandline_icon")); + setMessagePaneExpanded(true); + saveCollapsedState(); + enableResizeCtrls(true, true, true); + } } /*virtual*/ @@ -792,19 +908,33 @@ void LLFloaterIMSessionTab::onOpen(const LLSD& key) // Show the messages pane when opening a floater hosted in the Conversations host_floater->collapseMessagesPane(false); } + + mInputButtonPanel->setVisible(isTornOff()); } void LLFloaterIMSessionTab::onTearOffClicked() { - setFollows(isTornOff()? FOLLOWS_ALL : FOLLOWS_NONE); + restoreFloater(); + setFollows(isTornOff()? FOLLOWS_ALL : FOLLOWS_NONE); mSaveRect = isTornOff(); initRectControl(); LLFloater::onClickTearOff(this); + LLFloaterIMContainer* container = LLFloaterReg::findTypedInstance("im_container"); + if (isTornOff()) { + container->selectAdjacentConversation(false); forceReshape(); } + //Upon re-docking the torn off floater, select the corresponding conversation line item + else + { + container->selectConversation(mSessionID); + + } + mInputButtonPanel->setVisible(isTornOff()); + refreshConversation(); updateGearBtn(); } @@ -940,6 +1070,14 @@ LLConversationItem* LLFloaterIMSessionTab::getCurSelectedViewModelItem() return conversationItem; } +void LLFloaterIMSessionTab::saveCollapsedState() +{ + LLFloaterIMSessionTab* conversp = LLFloaterIMSessionTab::getConversation(mSessionID); + if(conversp->isNearbyChat()) + { + gSavedPerAccountSettings.setBOOL("NearbyChatIsNotCollapsed", isMessagePaneExpanded()); + } +} BOOL LLFloaterIMSessionTab::handleKeyHere(KEY key, MASK mask ) { if(mask == MASK_ALT) diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index d55b021df7..c7e73bd70d 100644 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -98,6 +98,10 @@ public: LLConversationItem* getCurSelectedViewModelItem(); void forceReshape(); virtual BOOL handleKeyHere( KEY key, MASK mask ); + bool isMessagePaneExpanded(){return mMessagePaneExpanded;} + void setMessagePaneExpanded(bool expanded){mMessagePaneExpanded = expanded;} + void restoreFloater(); + void saveCollapsedState(); protected: @@ -111,6 +115,8 @@ protected: bool onIMShowModesMenuItemCheck(const LLSD& userdata); bool onIMShowModesMenuItemEnable(const LLSD& userdata); static void onSlide(LLFloaterIMSessionTab *self); + static void onCollapseToLine(LLFloaterIMSessionTab *self); + void reshapeFloater(bool collapse); // refresh a visual state of the Call button void updateCallBtnState(bool callIsActive); @@ -135,17 +141,30 @@ protected: void appendMessage(const LLChat& chat, const LLSD &args = 0); std::string appendTime(); + void assignResizeLimits(); + + S32 mFloaterExtraWidth; bool mIsNearbyChat; bool mIsP2PChat; + bool mMessagePaneExpanded; + bool mIsParticipantListExpanded; + + LLIMModel::LLIMSession* mSession; // Participants list: model and view LLConversationViewParticipant* createConversationViewParticipant(LLConversationItem* item); LLUUID mSessionID; + LLLayoutStack* mBodyStack; + LLLayoutStack* mParticipantListAndHistoryStack; LLLayoutPanel* mParticipantListPanel; // add the widgets to that see mConversationsListPanel + LLLayoutPanel* mRightPartPanel; + LLLayoutPanel* mContentPanel; + LLLayoutPanel* mToolbarPanel; + LLLayoutPanel* mInputButtonPanel; LLParticipantList* getParticipantList(); conversations_widgets_map mConversationsWidgets; LLConversationViewModel mConversationViewModel; @@ -155,13 +174,17 @@ protected: LLOutputMonitorCtrl* mSpeakingIndicator; LLChatHistory* mChatHistory; LLChatEntry* mInputEditor; - int mInputEditorTopPad; // padding between input field and chat history + LLLayoutPanel * mChatLayoutPanel; + int mInputEditorPad; // padding between input field and chat history + LLButton* mExpandCollapseLineBtn; LLButton* mExpandCollapseBtn; LLButton* mTearOffBtn; LLButton* mCloseBtn; LLButton* mGearBtn; + S32 mFloaterHeight; + private: // Handling selection and contextual menu @@ -179,7 +202,7 @@ private: * and avoid overlapping, since input chat field can be vertically expanded. * Implementation: chat history bottom "follows" top+top_pad of input chat field */ - void reshapeChatHistory(); + void reshapeChatLayoutPanel(); bool checkIfTornOff(); bool mIsHostAttached; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 3f8c23ba83..a28af2101b 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -443,6 +443,8 @@ BOOL LLFloaterPreference::postBuild() std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); setCacheLocation(cache_location); + getChild("log_path_string")->setEnabled(FALSE); // make it read-only but selectable + getChild("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); getChild("FriendIMOptions")->setCommitCallback(boost::bind(&LLFloaterPreference::onNotificationsChange, this,"FriendIMOptions")); @@ -1572,7 +1574,6 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im getChildView("send_im_to_email")->setEnabled(TRUE); getChild("send_im_to_email")->setValue(im_via_email); getChildView("favorites_on_login_check")->setEnabled(TRUE); - getChildView("log_path_string")->setEnabled(FALSE);// LineEditor becomes readonly in this case. getChildView("log_path_button")->setEnabled(TRUE); getChildView("chat_font_size")->setEnabled(TRUE); } @@ -1667,7 +1668,10 @@ void LLFloaterPreference::onClickActionChange() void LLFloaterPreference::onDeleteTranscripts() { - LLNotificationsUtil::add("PreferenceChatDeleteTranscripts", LLSD(), LLSD(), boost::bind(&LLFloaterPreference::onDeleteTranscriptsResponse, this, _1, _2)); + LLSD args; + args["FOLDER"] = gDirUtilp->getUserName(); + + LLNotificationsUtil::add("PreferenceChatDeleteTranscripts", args, LLSD(), boost::bind(&LLFloaterPreference::onDeleteTranscriptsResponse, this, _1, _2)); } void LLFloaterPreference::onDeleteTranscriptsResponse(const LLSD& notification, const LLSD& response) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 8f3f5145a9..76a314f807 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -154,149 +154,156 @@ static void on_avatar_name_cache_toast(const LLUUID& agent_id, args["FROM"] = av_name.getCompleteName(); args["FROM_ID"] = msg["from_id"]; args["SESSION_ID"] = msg["session_id"]; + args["SESSION_TYPE"] = msg["session_type"]; LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID())); } void on_new_message(const LLSD& msg) { - std::string action; + std::string user_preferences; LLUUID participant_id = msg["from_id"].asUUID(); LLUUID session_id = msg["session_id"].asUUID(); LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); - // determine action for this session - - if (session_id.isNull()) - { - action = gSavedSettings.getString("NotificationNearbyChatOptions"); - } - else if(session->isP2PSessionType()) - { - if (LLAvatarTracker::instance().isBuddy(participant_id)) - { - action = gSavedSettings.getString("NotificationFriendIMOptions"); - } - else - { - action = gSavedSettings.getString("NotificationNonFriendIMOptions"); - } - } - else if(session->isAdHocSessionType()) - { - action = gSavedSettings.getString("NotificationConferenceIMOptions"); - } - else if(session->isGroupSessionType()) - { - action = gSavedSettings.getString("NotificationGroupChatOptions"); - } - // do not show notification which goes from agent if (gAgent.getID() == participant_id) { return; } - // execution of the action + // determine state of conversations floater + enum {CLOSED, NOT_ON_TOP, ON_TOP, ON_TOP_AND_ITEM_IS_SELECTED} conversations_floater_status; LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance("im_container"); + LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id); - if (im_box->isFrontmost() && im_box->getSelectedSession() == session_id) + if (!LLFloater::isVisible(im_box) || im_box->isMinimized()) { - return; + conversations_floater_status = CLOSED; + } + else if ( !im_box->hasFocus() && + (!session_floater || !LLFloater::isVisible(session_floater) + || session_floater->isMinimized() || !session_floater->hasFocus())) + { + conversations_floater_status = NOT_ON_TOP; + } + else if (im_box->getSelectedSession() != session_id) + { + conversations_floater_status = ON_TOP; + } + else + { + conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED; } - LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id); - - //session floater not focused (visible or not) - bool session_floater_not_focused = session_floater && !session_floater->hasFocus(); - - //conv. floater is closed - bool conversation_floater_is_closed = - !( im_box - && im_box->isInVisibleChain() - && !im_box->isMinimized()); - - //conversation floater not focused (visible or not) - bool conversation_floater_not_focused = - conversation_floater_is_closed || !im_box->hasFocus(); - // sess. floater is open - bool session_floater_is_open = - session_floater - && session_floater->isInVisibleChain() - && !session_floater->isMinimized() - && !(session_floater->getHost() && session_floater->getHost()->isMinimized()); - - if ("toast" == action && !session_floater_is_open) + // determine user prefs for this session + if (session_id.isNull()) { - //User is not focused on conversation containing the message - if(session_floater_not_focused) + user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions"); + } + else if(session->isP2PSessionType()) + { + if (LLAvatarTracker::instance().isBuddy(participant_id)) { - if(!LLMuteList::getInstance()->isMuted(participant_id)) - { - im_box->flashConversationItemWidget(session_id, true); - } - //The conversation floater isn't focused/open - if(conversation_floater_not_focused) - { - if(!LLMuteList::getInstance()->isMuted(participant_id) - && !gAgent.isDoNotDisturb()) - { - gToolBarView->flashCommand(LLCommandId("chat"), true); - } - - //Show IM toasts (upper right toasts) - // Skip toasting for system messages and for nearby chat - if(session_id.notNull() && participant_id.notNull()) - { - LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); - } - } - } + user_preferences = gSavedSettings.getString("NotificationFriendIMOptions"); + } + else + { + user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions"); + } + } + else if(session->isAdHocSessionType()) + { + user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions"); + } + else if(session->isGroupSessionType()) + { + user_preferences = gSavedSettings.getString("NotificationGroupChatOptions"); } - else if ("flash" == action) + // actions: + + // 0. nothing - exit + if (("none" == user_preferences || + ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status) + && session_floater->isMessagePaneExpanded()) { - if (!gAgent.isDoNotDisturb()) - { - im_box->flashConversationItemWidget(session_id, true); - if(conversation_floater_not_focused) + return; + } + + // 1. open floater and [optional] surface it + if ("openconversations" == user_preferences && + (CLOSED == conversations_floater_status + || NOT_ON_TOP == conversations_floater_status)) + { + if(!gAgent.isDoNotDisturb()) + { + // Open conversations floater + LLFloaterReg::showInstance("im_container"); + im_box->collapseMessagesPane(false); + if (session_floater) { - //User is not focused on conversation containing the message - gToolBarView->flashCommand(LLCommandId("chat"), true); + if (session_floater->getHost()) + { + if (NULL != im_box && im_box->isMinimized()) + { + LLFloater::onClickMinimize(im_box); + } + } + else + { + if (session_floater->isMinimized()) + { + LLFloater::onClickMinimize(session_floater); + } + } } } - else if(session_id.notNull() && participant_id.notNull()) - { - //If a DND message, allow notification to be stored so upon DND exit - //useMostItrusiveIMNotification will be called to notify user a message exists - LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); - } - } - - else if("openconversations" == action) - { - //User is not focused on conversation containing the message - if(session_floater_not_focused) + else { - //Flash line item - im_box->flashConversationItemWidget(session_id, true); - - if(!gAgent.isDoNotDisturb()) - { - //Surface conversations floater - LLFloaterReg::showInstance("im_container"); - } - - //If in DND mode, allow notification to be stored so upon DND exit + //If in DND mode, allow notification to be stored so upon DND exit //useMostItrusiveIMNotification will be called to notify user a message exists - if(session_id.notNull() - && participant_id.notNull() - && gAgent.isDoNotDisturb() - && !session_floater_is_open) + if(session_id.notNull() + && participant_id.notNull() + && !session_floater->isShown()) { LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); - } - } + } + } + } + + // 2. Flash line item + if ("openconversations" == user_preferences + || ON_TOP == conversations_floater_status) + { + if(!LLMuteList::getInstance()->isMuted(participant_id)) + { + im_box->flashConversationItemWidget(session_id, true); + } + } + + // 3. Flash FUI button + if (("toast" == user_preferences || "flash" == user_preferences) && + (CLOSED == conversations_floater_status + || NOT_ON_TOP == conversations_floater_status)) + { + if(!LLMuteList::getInstance()->isMuted(participant_id) + && !gAgent.isDoNotDisturb()) + { + gToolBarView->flashCommand(LLCommandId("chat"), true); + } + } + + // 4. Toast + if ("toast" == user_preferences + || !session_floater->isMessagePaneExpanded()) + { + //Show IM toasts (upper right toasts) + // Skip toasting for system messages and for nearby chat + if(session_id.notNull() && participant_id.notNull()) + { + LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg)); + } } } @@ -636,8 +643,7 @@ void LLIMModel::LLIMSession::loadHistory() LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const { - return get_if_there(mId2SessionMap, session_id, - (LLIMModel::LLIMSession*) NULL); + return get_if_there(mId2SessionMap, session_id, (LLIMModel::LLIMSession*) NULL); } //*TODO consider switching to using std::set instead of std::list for holding LLUUIDs across the whole code @@ -990,6 +996,7 @@ bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, co arg["from"] = from; arg["from_id"] = from_id; arg["time"] = LLLogChat::timestamp(false); + arg["session_type"] = session->mSessionType; mNewMsgSignal(arg); return true; @@ -2633,7 +2640,7 @@ void LLIMMgr::addMessage( if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly")) { // Evaluate if we need to skip this message when that setting is true (default is false) - LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id); skip_message = (LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL); // Skip non friends... skip_message &= !session->isGroupSessionType(); // Do not skip group chats... skip_message &= !(other_participant_id == gAgentID); // You are your best friend... Don't skip yourself @@ -2649,7 +2656,7 @@ void LLIMMgr::addMessage( { LLFloaterReg::showInstance("im_container"); LLFloaterReg::getTypedInstance("im_container")-> - flashConversationItemWidget(session_id, true); + flashConversationItemWidget(new_session_id, true); } } @@ -2804,7 +2811,7 @@ LLUUID LLIMMgr::addSession( } } - bool new_session = !LLIMModel::getInstance()->findIMSession(session_id); + bool new_session = (LLIMModel::getInstance()->findIMSession(session_id) == NULL); //works only for outgoing ad-hoc sessions if (new_session && IM_SESSION_CONFERENCE_START == dialog && ids.size()) diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 448100c5d6..2d7454b636 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -444,7 +444,7 @@ std::string LLLogChat::oldLogFileName(std::string filename) } // static -void LLLogChat::getListOfTranscriptFiles(std::vector& list_of_transcriptions) +void LLLogChat::findTranscriptFiles(std::string pattern, std::vector& list_of_transcriptions) { // get Users log directory std::string dirname = gDirUtilp->getPerAccountChatLogsDir(); @@ -452,9 +452,6 @@ void LLLogChat::getListOfTranscriptFiles(std::vector& list_of_trans // add final OS dependent delimiter dirname += gDirUtilp->getDirDelimiter(); - // create search pattern - std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION; - LLDirIterator iter(dirname, pattern); std::string filename; while (iter.next(filename)) @@ -490,6 +487,22 @@ void LLLogChat::getListOfTranscriptFiles(std::vector& list_of_trans } } +// static +void LLLogChat::getListOfTranscriptFiles(std::vector& list_of_transcriptions) +{ + // create search pattern + std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION; + findTranscriptFiles(pattern, list_of_transcriptions); +} + +// static +void LLLogChat::getListOfTranscriptBackupFiles(std::vector& list_of_transcriptions) +{ + // create search pattern + std::string pattern = "*." + LL_TRANSCRIPT_FILE_EXTENSION + ".backup*"; + findTranscriptFiles(pattern, list_of_transcriptions); +} + //static boost::signals2::connection LLLogChat::setSaveHistorySignal(const save_history_signal_t::slot_type& cb) { @@ -581,6 +594,7 @@ void LLLogChat::deleteTranscripts() { std::vector list_of_transcriptions; getListOfTranscriptFiles(list_of_transcriptions); + getListOfTranscriptBackupFiles(list_of_transcriptions); BOOST_FOREACH(const std::string& fullpath, list_of_transcriptions) { diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index 784786a565..e819f00dd9 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -49,7 +49,9 @@ public: const std::string& from, const LLUUID& from_id, const std::string& line); + static void findTranscriptFiles(std::string pattern, std::vector& list_of_transcriptions); static void getListOfTranscriptFiles(std::vector& list); + static void getListOfTranscriptBackupFiles(std::vector& list_of_transcriptions); static void loadChatHistory(const std::string& file_name, std::list& messages, const LLSD& load_params = LLSD()); diff --git a/indra/newview/llnotificationstorage.cpp b/indra/newview/llnotificationstorage.cpp index b6184f09bf..2923221c90 100644 --- a/indra/newview/llnotificationstorage.cpp +++ b/indra/newview/llnotificationstorage.cpp @@ -105,6 +105,8 @@ bool LLNotificationStorage::writeNotifications(const LLSD& pNotificationData) co bool LLNotificationStorage::readNotifications(LLSD& pNotificationData) const { + LL_INFOS("LLNotificationStorage") << "starting read '" << mFileName << "'" << LL_ENDL; + bool didFileRead; pNotificationData.clear(); @@ -126,6 +128,8 @@ bool LLNotificationStorage::readNotifications(LLSD& pNotificationData) const } } + LL_INFOS("LLNotificationStorage") << "ending read '" << mFileName << "'" << LL_ENDL; + return didFileRead; } diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index c5283404f1..4138558bad 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -611,10 +611,10 @@ BOOL LLPanelPeople::postBuild() mGroupList->setNoItemsMsg(getString("no_groups_msg")); mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg")); - mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); - mRecentList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); - mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); - mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); + mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyPeopleContextMenu); + mRecentList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); + mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); + mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gPeopleContextMenu); setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false); setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false); @@ -1143,7 +1143,10 @@ void LLPanelPeople::onGearButtonClicked(LLUICtrl* btn) uuid_vec_t selected_uuids; getCurrentItemIDs(selected_uuids); // Spawn at bottom left corner of the button. - LLPanelPeopleMenus::gNearbyMenu.show(btn, selected_uuids, 0, 0); + if (getActiveTabName() == NEARBY_TAB_NAME) + LLPanelPeopleMenus::gNearbyPeopleContextMenu.show(btn, selected_uuids, 0, 0); + else + LLPanelPeopleMenus::gPeopleContextMenu.show(btn, selected_uuids, 0, 0); } void LLPanelPeople::onImButtonClicked() diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp index 47d6b49a50..49f7361c4a 100644 --- a/indra/newview/llpanelpeoplemenus.cpp +++ b/indra/newview/llpanelpeoplemenus.cpp @@ -39,15 +39,18 @@ #include "llcallingcard.h" // for LLAvatarTracker #include "lllogchat.h" #include "llviewermenu.h" // for gMenuHolder +#include "llconversationmodel.h" +#include "llviewerobjectlist.h" namespace LLPanelPeopleMenus { -NearbyMenu gNearbyMenu; +PeopleContextMenu gPeopleContextMenu; +NearbyPeopleContextMenu gNearbyPeopleContextMenu; -//== NearbyMenu =============================================================== +//== PeopleContextMenu =============================================================== -LLContextMenu* NearbyMenu::createMenu() +LLContextMenu* PeopleContextMenu::createMenu() { // set up the callbacks for all of the avatar menu items LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; @@ -64,7 +67,8 @@ LLContextMenu* NearbyMenu::createMenu() registrar.add("Avatar.RemoveFriend", boost::bind(&LLAvatarActions::removeFriendDialog, id)); registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startIM, id)); registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startCall, id)); - registrar.add("Avatar.OfferTeleport", boost::bind(&NearbyMenu::offerTeleport, this)); + registrar.add("Avatar.OfferTeleport", boost::bind(&PeopleContextMenu::offerTeleport, this)); + registrar.add("Avatar.ZoomIn", boost::bind(&handle_zoom_to_object, id)); registrar.add("Avatar.ShowOnMap", boost::bind(&LLAvatarActions::showOnMap, id)); registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::share, id)); registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id)); @@ -72,33 +76,72 @@ LLContextMenu* NearbyMenu::createMenu() registrar.add("Avatar.InviteToGroup", boost::bind(&LLAvatarActions::inviteToGroup, id)); registrar.add("Avatar.Calllog", boost::bind(&LLAvatarActions::viewChatHistory, id)); - enable_registrar.add("Avatar.EnableItem", boost::bind(&NearbyMenu::enableContextMenuItem, this, _2)); - enable_registrar.add("Avatar.CheckItem", boost::bind(&NearbyMenu::checkContextMenuItem, this, _2)); + enable_registrar.add("Avatar.EnableItem", boost::bind(&PeopleContextMenu::enableContextMenuItem, this, _2)); + enable_registrar.add("Avatar.CheckItem", boost::bind(&PeopleContextMenu::checkContextMenuItem, this, _2)); // create the context menu from the XUI menu = createFromFile("menu_people_nearby.xml"); + buildContextMenu(*menu, 0x0); } else { // Set up for multi-selected People // registrar.add("Avatar.AddFriend", boost::bind(&LLAvatarActions::requestFriendshipDialog, mUUIDs)); // *TODO: unimplemented - registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startConference, mUUIDs, LLUUID::null)); - registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startAdhocCall, mUUIDs, LLUUID::null)); - registrar.add("Avatar.OfferTeleport", boost::bind(&NearbyMenu::offerTeleport, this)); - registrar.add("Avatar.RemoveFriend",boost::bind(&LLAvatarActions::removeFriendsDialog, mUUIDs)); + registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startConference, mUUIDs, LLUUID::null)); + registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startAdhocCall, mUUIDs, LLUUID::null)); + registrar.add("Avatar.OfferTeleport", boost::bind(&PeopleContextMenu::offerTeleport, this)); + registrar.add("Avatar.RemoveFriend", boost::bind(&LLAvatarActions::removeFriendsDialog, mUUIDs)); // registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::startIM, mUUIDs)); // *TODO: unimplemented - // registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, mUUIDs)); // *TODO: unimplemented - enable_registrar.add("Avatar.EnableItem", boost::bind(&NearbyMenu::enableContextMenuItem, this, _2)); + // registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, mUUIDs)); // *TODO: unimplemented + + enable_registrar.add("Avatar.EnableItem", boost::bind(&PeopleContextMenu::enableContextMenuItem, this, _2)); // create the context menu from the XUI menu = createFromFile("menu_people_nearby_multiselect.xml"); + buildContextMenu(*menu, ITEM_IN_MULTI_SELECTION); } return menu; } -bool NearbyMenu::enableContextMenuItem(const LLSD& userdata) +void PeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags) +{ + menuentry_vec_t items; + menuentry_vec_t disabled_items; + + if (flags & ITEM_IN_MULTI_SELECTION) + { + items.push_back(std::string("add_friends")); + items.push_back(std::string("remove_friends")); + items.push_back(std::string("im")); + items.push_back(std::string("call")); + items.push_back(std::string("share")); + items.push_back(std::string("pay")); + items.push_back(std::string("offer_teleport")); + } + else + { + items.push_back(std::string("view_profile")); + items.push_back(std::string("im")); + items.push_back(std::string("offer_teleport")); + items.push_back(std::string("voice_call")); + items.push_back(std::string("chat_history")); + items.push_back(std::string("separator_chat_history")); + items.push_back(std::string("add_friend")); + items.push_back(std::string("remove_friend")); + items.push_back(std::string("invite_to_group")); + items.push_back(std::string("separator_invite_to_group")); + items.push_back(std::string("map")); + items.push_back(std::string("share")); + items.push_back(std::string("pay")); + items.push_back(std::string("block_unblock")); + } + + hide_context_entries(menu, items, disabled_items); +} + +bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata) { if(gAgent.getID() == mUUIDs.front()) { @@ -170,6 +213,12 @@ bool NearbyMenu::enableContextMenuItem(const LLSD& userdata) { return LLAvatarActions::canCall(); } + else if (item == std::string("can_zoom_in")) + { + const LLUUID& id = mUUIDs.front(); + + return gObjectList.findObject(id); + } else if (item == std::string("can_show_on_map")) { const LLUUID& id = mUUIDs.front(); @@ -193,7 +242,7 @@ bool NearbyMenu::enableContextMenuItem(const LLSD& userdata) return false; } -bool NearbyMenu::checkContextMenuItem(const LLSD& userdata) +bool PeopleContextMenu::checkContextMenuItem(const LLSD& userdata) { std::string item = userdata.asString(); const LLUUID& id = mUUIDs.front(); @@ -206,11 +255,50 @@ bool NearbyMenu::checkContextMenuItem(const LLSD& userdata) return false; } -void NearbyMenu::offerTeleport() +void PeopleContextMenu::offerTeleport() { // boost::bind cannot recognize overloaded method LLAvatarActions::offerTeleport(), // so we have to use a wrapper. LLAvatarActions::offerTeleport(mUUIDs); } +//== NearbyPeopleContextMenu =============================================================== + +void NearbyPeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags) +{ + menuentry_vec_t items; + menuentry_vec_t disabled_items; + + if (flags & ITEM_IN_MULTI_SELECTION) + { + items.push_back(std::string("add_friends")); + items.push_back(std::string("remove_friends")); + items.push_back(std::string("im")); + items.push_back(std::string("call")); + items.push_back(std::string("share")); + items.push_back(std::string("pay")); + items.push_back(std::string("offer_teleport")); + } + else + { + items.push_back(std::string("view_profile")); + items.push_back(std::string("im")); + items.push_back(std::string("offer_teleport")); + items.push_back(std::string("voice_call")); + items.push_back(std::string("chat_history")); + items.push_back(std::string("separator_chat_history")); + items.push_back(std::string("add_friend")); + items.push_back(std::string("remove_friend")); + items.push_back(std::string("invite_to_group")); + items.push_back(std::string("separator_invite_to_group")); + items.push_back(std::string("zoom_in")); + items.push_back(std::string("map")); + items.push_back(std::string("share")); + items.push_back(std::string("pay")); + items.push_back(std::string("block_unblock")); + } + + hide_context_entries(menu, items, disabled_items); +} + } // namespace LLPanelPeopleMenus diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h index d51eaec716..0a1dcef303 100644 --- a/indra/newview/llpanelpeoplemenus.h +++ b/indra/newview/llpanelpeoplemenus.h @@ -33,19 +33,33 @@ namespace LLPanelPeopleMenus { /** - * Menu used in the nearby people list. + * Menu used in the people lists. */ -class NearbyMenu : public LLListContextMenu +class PeopleContextMenu : public LLListContextMenu { public: /*virtual*/ LLContextMenu* createMenu(); + +protected: + virtual void buildContextMenu(class LLMenuGL& menu, U32 flags); + private: bool enableContextMenuItem(const LLSD& userdata); bool checkContextMenuItem(const LLSD& userdata); void offerTeleport(); }; -extern NearbyMenu gNearbyMenu; +/** + * Menu used in the nearby people list. + */ +class NearbyPeopleContextMenu : public PeopleContextMenu +{ +protected: + /*virtual*/ void buildContextMenu(class LLMenuGL& menu, U32 flags); +}; + +extern PeopleContextMenu gPeopleContextMenu; +extern NearbyPeopleContextMenu gNearbyPeopleContextMenu; } // namespace LLPanelPeopleMenus diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp index 11c12e6c10..666f10df96 100644 --- a/indra/newview/llpersistentnotificationstorage.cpp +++ b/indra/newview/llpersistentnotificationstorage.cpp @@ -87,6 +87,8 @@ void LLPersistentNotificationStorage::loadNotifications() { LLFastTimer _(FTM_LOAD_NOTIFICATIONS); + LL_INFOS("LLPersistentNotificationStorage") << "start loading notifications" << LL_ENDL; + LLNotifications::instance().getChannel("Persistent")-> connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1)); @@ -129,6 +131,8 @@ void LLPersistentNotificationStorage::loadNotifications() notification_channel->hideToast(notification->getID()); } } + + LL_INFOS("LLPersistentNotificationStorage") << "finished loading notifications" << LL_ENDL; } bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& payload) diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 05df7261e1..8783d99b11 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -38,6 +38,8 @@ #include "llvoavatar.h" #include "llworld.h" +extern LLControlGroup gSavedSettings; + const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f); const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f); @@ -311,6 +313,7 @@ LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : mModerateModeHandledFirstTime(false), mSpeakerListUpdated(false) { + mGetListTime.reset(); static LLUICachedControl remove_delay ("SpeakerParticipantRemoveDelay", 10.0); mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay); @@ -409,12 +412,10 @@ void LLSpeakerMgr::update(BOOL resort_ok) // update status of all current speakers BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();) + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); speaker_it++) { LLUUID speaker_id = speaker_it->first; LLSpeaker* speakerp = speaker_it->second; - - speaker_map_t::iterator cur_speaker_it = speaker_it++; if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) { @@ -539,30 +540,39 @@ void LLSpeakerMgr::updateSpeakerList() LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); if (session->isGroupSessionType() && (mSpeakers.size() <= 1)) { + const F32 load_group_timeout = gSavedSettings.getF32("ChatLoadGroupTimeout"); // For groups, we need to hit the group manager. // Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail. LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id); - if (!gdatap) + if (!gdatap && (mGetListTime.getElapsedTimeF32() >= load_group_timeout)) { // Request the data the first time around LLGroupMgr::getInstance()->sendCapGroupMembersRequest(session_id); } - else if (gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) + else if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) { // Add group members when we get the complete list (note: can take a while before we get that list) LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin(); + const S32 load_group_max_members = gSavedSettings.getS32("ChatLoadGroupMaxMembers"); + S32 updated = 0; while (member_it != gdatap->mMembers.end()) { LLGroupMemberData* member = member_it->second; - // Add only the members who are online - if (member->getOnlineStatus() == "Online") + LLUUID id = member_it->first; + // Add only members who are online and not already in the list + if ((member->getOnlineStatus() == "Online") && (mSpeakers.find(id) == mSpeakers.end())) { - LLPointer speakerp = setSpeaker(member_it->first, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); + LLPointer speakerp = setSpeaker(id, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT); speakerp->mIsModerator = ((member->getAgentPowers() & GP_SESSION_MODERATOR) == GP_SESSION_MODERATOR); + updated++; } ++member_it; + // Limit the number of "manually updated" participants to a reasonable number to avoid severe fps drop + // *TODO : solve the perf issue of having several hundreds of widgets in the conversation list + if (updated >= load_group_max_members) + break; } - mSpeakerListUpdated = true; + mSpeakerListUpdated = true; } } else if (mSpeakers.size() == 0) diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 5f5095097e..e953dd0e1a 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -264,6 +264,7 @@ protected: typedef std::map > speaker_map_t; speaker_map_t mSpeakers; bool mSpeakerListUpdated; + LLTimer mGetListTime; speaker_list_t mSpeakersSorted; LLFrameTimer mSpeechTimer; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index ffeea2f4df..40577118ba 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1038,7 +1038,6 @@ void render_hud_attachments() if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices()) { LLCamera hud_cam = *LLViewerCamera::getInstance(); - LLVector3 origin = hud_cam.getOrigin(); hud_cam.setOrigin(-1.f,0,0); hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1)); LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 2340436a01..a13c793899 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2382,7 +2382,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLPostponedNotification::add(params, from_id, false); break; - case IM_NOTHING_SPECIAL: + case IM_NOTHING_SPECIAL: // p2p IM // Don't show dialog, just do IM if (!gAgent.isGodlike() && gAgent.getRegion()->isPrelude() @@ -2783,47 +2783,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } break; - case IM_SESSION_SEND: - { - if (is_do_not_disturb) - { - return; - } - - // Only show messages if we have a session open (which - // should happen after you get an "invitation" - if ( !gIMMgr->hasSession(session_id) ) - { - return; - } - - // standard message, not from system - std::string saved; - if(offline == IM_OFFLINE) - { - saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); - } - buffer = saved + message; - BOOL is_this_agent = FALSE; - if(from_id == gAgentID) - { - is_this_agent = TRUE; - } - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - IM_OFFLINE == offline, - ll_safe_string((char*)binary_bucket), - IM_SESSION_INVITE, - parent_estate_id, - region_id, - position, - true); - } - break; - case IM_FROM_TASK: { if (is_do_not_disturb && !is_owned_by_me) @@ -2922,6 +2881,76 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLPostponedNotification::add(params, from_id, from_group); } break; + + case IM_SESSION_SEND: // ad-hoc or group IMs + + // Only show messages if we have a session open (which + // should happen after you get an "invitation" + if ( !gIMMgr->hasSession(session_id) ) + { + return; + } + + else if (offline == IM_ONLINE && is_do_not_disturb) + { + + // return a standard "do not disturb" message, but only do it to online IM + // (i.e. not other auto responses and not store-and-forward IM) + if (!gIMMgr->hasSession(session_id)) + { + // if there is not a panel for this conversation (i.e. it is a new IM conversation + // initiated by the other party) then... + send_do_not_disturb_message(msg, from_id, session_id); + } + + // now store incoming IM in chat history + + buffer = message; + + LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + + // add to IM panel, but do not bother the user + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + IM_OFFLINE == offline, + ll_safe_string((char*)binary_bucket), + IM_SESSION_INVITE, + parent_estate_id, + region_id, + position, + true); + } + else + { + // standard message, not from system + std::string saved; + if(offline == IM_OFFLINE) + { + saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); + } + + buffer = saved + message; + + LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + IM_OFFLINE == offline, + ll_safe_string((char*)binary_bucket), + IM_SESSION_INVITE, + parent_estate_id, + region_id, + position, + true); + } + break; + case IM_FROM_TASK_AS_ALERT: if (is_do_not_disturb && !is_owned_by_me) { diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index e44a2cc4df..4afd90b44c 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2827,7 +2827,6 @@ void LLViewerWindow::updateUI() BOOL handled = FALSE; - BOOL handled_by_top_ctrl = FALSE; LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); LLView* captor_view = dynamic_cast(mouse_captor); @@ -3012,7 +3011,6 @@ void LLViewerWindow::updateUI() S32 local_x, local_y; top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask); - handled_by_top_ctrl = TRUE; } if ( !handled ) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 157be08f45..a3093f069d 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -675,7 +675,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mBelowWater(FALSE), mLastAppearanceBlendTime(0.f), mAppearanceAnimating(FALSE), - mNameString(), + mNameIsSet(false), mTitle(), mNameAway(false), mNameDoNotDisturb(false), @@ -2994,43 +2994,43 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) return; } - BOOL new_name = FALSE; - if (visible_chat != mVisibleChat) - { - mVisibleChat = visible_chat; - new_name = TRUE; - } - - if (sRenderGroupTitles != mRenderGroupTitles) - { - mRenderGroupTitles = sRenderGroupTitles; - new_name = TRUE; - } + BOOL new_name = FALSE; + if (visible_chat != mVisibleChat) + { + mVisibleChat = visible_chat; + new_name = TRUE; + } - // First Calculate Alpha - // If alpha > 0, create mNameText if necessary, otherwise delete it - F32 alpha = 0.f; - if (mAppAngle > 5.f) - { - const F32 START_FADE_TIME = NAME_SHOW_TIME - FADE_DURATION; - if (!visible_chat && sRenderName == RENDER_NAME_FADE && time_visible > START_FADE_TIME) - { - alpha = 1.f - (time_visible - START_FADE_TIME) / FADE_DURATION; - } - else - { - // ...not fading, full alpha - alpha = 1.f; - } - } - else if (mAppAngle > 2.f) - { - // far away is faded out also - alpha = (mAppAngle-2.f)/3.f; - } + if (sRenderGroupTitles != mRenderGroupTitles) + { + mRenderGroupTitles = sRenderGroupTitles; + new_name = TRUE; + } + + // First Calculate Alpha + // If alpha > 0, create mNameText if necessary, otherwise delete it + F32 alpha = 0.f; + if (mAppAngle > 5.f) + { + const F32 START_FADE_TIME = NAME_SHOW_TIME - FADE_DURATION; + if (!visible_chat && sRenderName == RENDER_NAME_FADE && time_visible > START_FADE_TIME) + { + alpha = 1.f - (time_visible - START_FADE_TIME) / FADE_DURATION; + } + else + { + // ...not fading, full alpha + alpha = 1.f; + } + } + else if (mAppAngle > 2.f) + { + // far away is faded out also + alpha = (mAppAngle-2.f)/3.f; + } if (alpha <= 0.f) - { + { if (mNameText) { mNameText->markDead(); @@ -3040,19 +3040,19 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) return; } - if (!mNameText) - { + if (!mNameText) + { mNameText = static_cast( LLHUDObject::addHUDObject( LLHUDObject::LL_HUD_NAME_TAG) ); //mNameText->setMass(10.f); - mNameText->setSourceObject(this); + mNameText->setSourceObject(this); mNameText->setVertAlignment(LLHUDNameTag::ALIGN_VERT_TOP); - mNameText->setVisibleOffScreen(TRUE); - mNameText->setMaxLines(11); - mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f); - sNumVisibleChatBubbles++; - new_name = TRUE; - } + mNameText->setVisibleOffScreen(TRUE); + mNameText->setMaxLines(11); + mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f); + sNumVisibleChatBubbles++; + new_name = TRUE; + } idleUpdateNameTagPosition(root_pos_last); idleUpdateNameTagText(new_name); @@ -3096,7 +3096,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) } // Rebuild name tag if state change detected - if (mNameString.empty() + if (!mNameIsSet || new_name || (!title && !mTitle.empty()) || (title && mTitle != title->getString()) @@ -3291,18 +3291,18 @@ void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, { mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font); } - mNameString += line; - mNameString += '\n'; + mNameIsSet |= !line.empty(); } void LLVOAvatar::clearNameTag() { - mNameString.clear(); + mNameIsSet = false; if (mNameText) { mNameText->setLabel(""); - mNameText->setString( "" ); + mNameText->setString(""); } + mTimeVisible.reset(); } //static diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index c59a3a150c..9f1f209920 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -939,7 +939,7 @@ protected: static void getAnimLabels(LLDynamicArray* labels); static void getAnimNames(LLDynamicArray* names); private: - std::string mNameString; // UTF-8 title + name + status + bool mNameIsSet; std::string mTitle; bool mNameAway; bool mNameDoNotDisturb; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index f3342b7ff1..c3cc90f040 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -1258,7 +1258,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateCreatingSessionGroup case stateCreatingSessionGroup: - if(mSessionTerminateRequested || !mVoiceEnabled && mIsInitialized) + if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized)) { // *TODO: Question: is this the right way out of this state setState(stateSessionTerminated); @@ -1274,7 +1274,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateRetrievingParcelVoiceInfo case stateRetrievingParcelVoiceInfo: // wait until parcel voice info is received. - if(mSessionTerminateRequested || !mVoiceEnabled && mIsInitialized) + if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized)) { // if a terminate request has been received, // bail and go to the stateSessionTerminated @@ -1294,7 +1294,7 @@ void LLVivoxVoiceClient::stateMachine() // Otherwise, if you log in but don't join a proximal channel (such as when your login location has voice disabled), your friends list won't sync. sendFriendsListUpdates(); - if(mSessionTerminateRequested || !mVoiceEnabled && mIsInitialized) + if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized)) { // TODO: Question: Is this the right way out of this state? setState(stateSessionTerminated); @@ -1442,7 +1442,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateRunning case stateRunning: // steady state // Disabling voice or disconnect requested. - if(!mVoiceEnabled && mIsInitialized || mSessionTerminateRequested) + if((!mVoiceEnabled && mIsInitialized) || mSessionTerminateRequested) { leaveAudioSession(); } @@ -2671,33 +2671,19 @@ void LLVivoxVoiceClient::checkFriend(const LLUUID& id) { buddyListEntry *buddy = findBuddy(id); - // Make sure we don't add a name before it's been looked up. + // Make sure we don't add a name before it's been looked up in the avatar name cache LLAvatarName av_name; - if(LLAvatarNameCache::get(id, &av_name)) + if (LLAvatarNameCache::get(id, &av_name)) { - // *NOTE: For now, we feed legacy names to Vivox because I don't know - // if their service can support a mix of new and old clients with - // different sorts of names. + // *NOTE: We feed legacy names to Vivox because we don't know if their service + // can support a mix of new and old clients with different sorts of names. std::string name = av_name.getAccountName(); - - const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id); - bool canSeeMeOnline = false; - if(relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS)) - canSeeMeOnline = true; - // When we get here, mNeedsSend is true and mInSLFriends is false. Change them as necessary. - - if(buddy) + if (buddy) { - // This buddy is already in both lists. - - if(name != buddy->mDisplayName) - { - // The buddy is in the list with the wrong name. Update it with the correct name. - LL_WARNS("Voice") << "Buddy " << id << " has wrong name (\"" << buddy->mDisplayName << "\" should be \"" << name << "\"), updating."<< LL_ENDL; - buddy->mDisplayName = name; - buddy->mNeedsNameUpdate = true; // This will cause the buddy to be resent. - } + // This buddy is already in both lists (vivox buddies and avatar cache). + // Trust the avatar cache more for the display name (vivox display name are notoriously wrong) + buddy->mDisplayName = name; } else { @@ -2706,20 +2692,19 @@ void LLVivoxVoiceClient::checkFriend(const LLUUID& id) buddy->mUUID = id; } - // In all the above cases, the buddy is in the SL friends list (which is how we got here). - buddy->mInSLFriends = true; - buddy->mCanSeeMeOnline = canSeeMeOnline; + const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id); + buddy->mCanSeeMeOnline = (relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS)); + // In all the above cases, the buddy is in the SL friends list and tha name has been resolved (which is how we got here). buddy->mNameResolved = true; - + buddy->mInSLFriends = true; } else { - // This name hasn't been looked up yet. Don't do anything with this buddy list entry until it has. - if(buddy) + // This name hasn't been looked up yet in the avatar cache. Don't do anything with this buddy list entry until it has. + if (buddy) { buddy->mNameResolved = false; } - // Initiate a lookup. // The "lookup completed" callback will ensure that the friends list is rechecked after it completes. lookupName(id); @@ -2827,13 +2812,12 @@ void LLVivoxVoiceClient::sendFriendsListUpdates() { std::ostringstream stream; - if(buddy->mInSLFriends && (!buddy->mInVivoxBuddies || buddy->mNeedsNameUpdate)) + if(buddy->mInSLFriends && !buddy->mInVivoxBuddies) { if(mNumberOfAliases > 0) { // Add (or update) this entry in the vivox buddy list buddy->mInVivoxBuddies = true; - buddy->mNeedsNameUpdate = false; LL_DEBUGS("Voice") << "add/update " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; stream << "" @@ -5859,7 +5843,6 @@ LLVivoxVoiceClient::buddyListEntry::buddyListEntry(const std::string &uri) : mNameResolved = false; mInVivoxBuddies = false; mInSLFriends = false; - mNeedsNameUpdate = false; } void LLVivoxVoiceClient::processBuddyListEntry(const std::string &uri, const std::string &displayName) @@ -5884,25 +5867,21 @@ LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::stri buddyListEntry *result = NULL; buddyListMap::iterator iter = mBuddyListMap.find(uri); - if(iter != mBuddyListMap.end()) + if (iter != mBuddyListMap.end()) { // Found a matching buddy already in the map. LL_DEBUGS("Voice") << "adding existing buddy " << uri << LL_ENDL; result = iter->second; } - if(!result) + if (!result) { // participant isn't already in one list or the other. LL_DEBUGS("Voice") << "adding new buddy " << uri << LL_ENDL; result = new buddyListEntry(uri); result->mDisplayName = displayName; - if(IDFromName(uri, result->mUUID)) - { - // Extracted UUID from name successfully. - } - else + if (!IDFromName(uri, result->mUUID)) { LL_DEBUGS("Voice") << "Couldn't find ID for buddy " << uri << " (\"" << displayName << "\")" << LL_ENDL; } @@ -7272,7 +7251,7 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr) void LLVivoxProtocolParser::EndTag(const char *tag) { const std::string& string = textBuffer; - + responseDepth--; if (ignoringTags) @@ -7371,6 +7350,8 @@ void LLVivoxProtocolParser::EndTag(const char *tag) } else if (!stricmp("Buddy", tag)) { + // NOTE : Vivox does *not* give reliable display name for Buddy tags + // We don't take those very seriously as a result... LLVivoxVoiceClient::getInstance()->processBuddyListEntry(uriString, displayNameString); } else if (!stricmp("BlockRule", tag)) diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 574027de42..a6f40eb3e9 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -584,7 +584,6 @@ protected: bool mNameResolved; bool mInSLFriends; bool mInVivoxBuddies; - bool mNeedsNameUpdate; }; typedef std::map buddyListMap; diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index ccc513b80d..11b2770ec0 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -965,8 +965,6 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& S32 text_x = x; S32 text_y = (S32)(y - sTrackCircleImage->getHeight()/2 - font->getLineHeight()); - BOOL is_in_window = true; - if( x < 0 || y < 0 || x >= getRect().getWidth() @@ -979,7 +977,6 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& text_x = sTrackingArrowX; text_y = sTrackingArrowY; } - is_in_window = false; } else if (LLTracker::getTrackingStatus() == LLTracker::TRACKING_LOCATION && LLTracker::getTrackedLocationType() != LLTracker::LOCATION_NOTHING) diff --git a/indra/newview/skins/default/textures/icons/collapse_to_one_line.png b/indra/newview/skins/default/textures/icons/collapse_to_one_line.png new file mode 100644 index 0000000000..d57144a645 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/collapse_to_one_line.png differ diff --git a/indra/newview/skins/default/textures/icons/expand_one_liner.png b/indra/newview/skins/default/textures/icons/expand_one_liner.png new file mode 100644 index 0000000000..58b7d90131 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/expand_one_liner.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index a07d7e4855..93c9cb02cb 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -171,6 +171,8 @@ with the same filename but different name + + diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml index 12c1676127..65f623a47e 100644 --- a/indra/newview/skins/default/xui/en/floater_im_container.xml +++ b/indra/newview/skins/default/xui/en/floater_im_container.xml @@ -61,7 +61,7 @@ image_unselected="Toolbar_Middle_Off" menu_filename="menu_participant_view.xml" layout="topleft" - left="10" + left="5" name="sort_btn" tool_tip="View/sort options" top="5" @@ -75,7 +75,7 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left_pad="4" + left_pad="2" name="add_btn" tool_tip="Start a new conversation" width="31"/> @@ -88,7 +88,7 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left_pad="4" + left_pad="2" name="speak_btn" tool_tip="Speak with people using your microphone" width="31"/> @@ -114,7 +114,7 @@ Conv_toolbar_open_call Conv_toolbar_hang_up + + @@ -65,14 +70,28 @@ top="0" left="0" height="355" - width="394"> - + + + @@ -126,7 +145,7 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left_pad="4" + left_pad="2" name="voice_call_btn" tool_tip="Open voice connection" width="31"/> @@ -151,7 +170,7 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left="283" + left="292" name="close_btn" tool_tip="End this conversation" width="31" /> @@ -164,7 +183,7 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left_pad="5" + left_pad="2" name="expand_collapse_btn" tool_tip="Collapse/Expand this pane" width="31" /> @@ -177,15 +196,22 @@ image_unselected="Toolbar_Middle_Off" layout="topleft" top="5" - left_pad="5" + left_pad="2" name="tear_off_btn" width="31" /> - + + + auto_resize="false"> + left="5" + top="0" + bottom="1"> - + + + + + + - + + +