diff --git a/configuration/buildAndUpdateProduct.sh b/configuration/buildAndUpdateProduct.sh index a4f1c035436..f0b197a6b57 100755 --- a/configuration/buildAndUpdateProduct.sh +++ b/configuration/buildAndUpdateProduct.sh @@ -1,5 +1,6 @@ #!/bin/bash set -o functrace +source ./configuration/correctFilePathInRelationToCurrentOs.sh # This indicates the type of the project # and is used to correctly resolve bundle names @@ -23,7 +24,7 @@ find_project_home () return 0 fi - echo $1 | sed -e 's/\/cygdrive\/\([a-zA-Z]\)/\1:/' + echo $(correct_file_path "$1") } # this holds for default installation @@ -40,8 +41,9 @@ if [[ "$PROJECT_HOME" == "" ]]; then exit 1 fi +#reading the filepath and editing it, so it fits for eclipse #currently save works for cygwin, gitbash and linux if [ "$SERVERS_HOME" = "" ]; then - SERVERS_HOME=`echo "$USER_HOME/servers" | sed -e 's/\/cygdrive\/\([a-zA-Z]\)/\1:/'` + SERVERS_HOME=$(correct_file_path "$USER_HOME/servers") fi # x86 or x86_64 should work for most cases diff --git a/configuration/correctFilePathInRelationToCurrentOs.sh b/configuration/correctFilePathInRelationToCurrentOs.sh new file mode 100644 index 00000000000..5c81db5b6a7 --- /dev/null +++ b/configuration/correctFilePathInRelationToCurrentOs.sh @@ -0,0 +1,17 @@ +#!/bin/bash +#editing the filepath, so it fits for operating system #currently savely works for cygwin, gitbash and linux +correct_file_path() +{ + if [[ "$1" == '/' ]] || [[ "$1" == "" ]]; then + echo "" + return 0 + fi + + if [ "$OSTYPE" == "cygwin" ]; then + echo $1 | sed 's/^\/cygdrive\/\([a-zA-Z]\)\//\1:\//' + elif [ "$OSTYPE" == "msys" ]; then + echo $1 | sed 's/^\/\([a-zA-Z]\)\//\1:\//' + else + echo $1 + fi +} \ No newline at end of file diff --git a/java/com.sap.sailing.dashboards.gwt/build.properties b/java/com.sap.sailing.dashboards.gwt/build.properties old mode 100644 new mode 100755 diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingInvitationMailBuilder.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingInvitationMailBuilder.java index 4af566fec30..3804f73b9e2 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingInvitationMailBuilder.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingInvitationMailBuilder.java @@ -85,7 +85,7 @@ class RaceLogTrackingInvitationMailBuilder { } RaceLogTrackingInvitationMailBuilder addEventLogo(final Event event) { - final List imagesWithTag = event.findImagesWithTag(MediaTagConstants.LOGO); + final List imagesWithTag = event.findImagesWithTag(MediaTagConstants.LOGO.getName()); if (imagesWithTag != null && !imagesWithTag.isEmpty()) { final ImageDescriptor imageDescriptor = imagesWithTag.get(0); final String logoUrl = imageDescriptor.getURL().toString(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java index 84d0b07641d..fdf9ae5cb14 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java @@ -309,11 +309,11 @@ public abstract class EventBaseImpl implements EventBase { ImageDescriptor image = migrateImageURLtoImage(url, getStartDate(), imageSizes.get(url)); String urlAsString = url.toString(); if (urlAsString.toLowerCase().indexOf("stage") > 0) { - image.addTag(MediaTagConstants.STAGE); + image.addTag(MediaTagConstants.STAGE.getName()); } else if (urlAsString.toLowerCase().indexOf("eventteaser") > 0) { - image.addTag(MediaTagConstants.TEASER); + image.addTag(MediaTagConstants.TEASER.getName()); } else { - image.addTag(MediaTagConstants.GALLERY); + image.addTag(MediaTagConstants.GALLERY.getName()); } addImage(image); changed = true; @@ -322,7 +322,7 @@ public abstract class EventBaseImpl implements EventBase { for (URL url : sponsorImageURLs) { if (!hasMedia(images, url)) { ImageDescriptor image = migrateImageURLtoImage(url, getStartDate(), imageSizes.get(url)); - image.addTag(MediaTagConstants.SPONSOR); + image.addTag(MediaTagConstants.SPONSOR.getName()); addImage(image); changed = true; } @@ -330,7 +330,7 @@ public abstract class EventBaseImpl implements EventBase { if (logoImageURL != null && !hasMedia(images, logoImageURL)) { ImageDescriptor image = migrateImageURLtoImage(logoImageURL, getStartDate(), imageSizes.get(logoImageURL)); - image.addTag(MediaTagConstants.LOGO); + image.addTag(MediaTagConstants.LOGO.getName()); addImage(image); changed = true; } diff --git a/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/impl/RPDMessageParsingTest.java b/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/impl/RPDMessageParsingTest.java index 5b29f1da512..d09fe4dc6c0 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/impl/RPDMessageParsingTest.java +++ b/java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/impl/RPDMessageParsingTest.java @@ -22,6 +22,17 @@ public class RPDMessageParsingTest { @Test public void parseRPDMessage() throws InterruptedException, ParseException, UnknownHostException, IOException { final String rpdMessage = "RPD|8aaa6db1-2084-4067-bf0b-2c24481b42da|2,|2018-09-13T15:06:39+09:00|14:50:00|00:16:39|2|315|97|03a52cb2-8a24-49d7-aebb-7e760be763a3;5;0;35.284932;139.516334;0.0;;;270;;;;;|0a66267e-3551-48e8-9872-adee288ceea4;5;229;35.287947;139.524639;0.8;;;312;;;;;|0b9e8236-f163-478e-8db9-67a4439db253;5;0;35.242476;139.5462;0.2;;;90;;;;;|0f06f40f-09de-49f6-9024-69aca52e387b;5;0;35.250663;139.556997;0.2;;;39;;;;;|0f1a7451-d242-4e8f-90b1-b00585356c0e;3;0;35.240411;139.546359;0.0;;;203;;;;;|0f519aeb-fb96-422b-83c9-6018dead3d22;3;0;35.247031;139.512632;0.4;;;296;;;;;|118d1ea9-ff87-4591-89d9-6cc58a5251d1;3;0;35.286932;139.511812;0.8;;;306;;;;;|152ae7ba-930a-43d2-a1dd-89e6ff60a3d0;3;0;35.241575;139.537837;0.2;;;158;;;;;|16fa57f0-10f4-4ac8-8fc0-4b8c875ebd33;5;0;35.256665;139.519313;1.0;;;64;;;;;|1db8195b-f5e2-4df1-af6d-e87386d224b9;5;0;35.290532;139.517897;0.6;;;270;;;;;|1ebbc2d1-78ed-420f-beec-9fad8fd5daa4;5;0;35.293927;139.511108;0.6;;;337;;;;;|1f32b277-ad3a-4ca7-9323-bc4458b971b7;5;0;35.28621;139.517586;0.6;;;291;;;;;|23fe9e60-7a93-4d58-b5a0-b73e51fff893;3;0;35.291366;139.495241;0.0;;;124;;;;;|244c5fc7-bf67-46e0-a6f1-d4d052c873be;5;0;35.243593;139.537314;0.4;;;360;;;;;|26229b56-4775-4a96-a611-a7e1de9781fd;5;0;35.299624;139.483962;0.0;;;219;;;;;|32f27c17-4c23-4770-973f-190cf08d6aa8;5;0;35.248049;139.54433;3.9;;;231;;;;;|35e389df-91df-4002-831b-7687d53e0ae5;5;0;35.274886;139.537612;2.1;;;123;;;;;|39217d61-9712-4e2b-b273-46cb3dfe67b9;5;0;35.290478;139.517889;0.6;;;287;;;;;|3ab16d2e-3913-4eee-94d7-ba0b5ea6ba6e;5;0;35.288054;139.512915;0.2;;;248;;;;;|3b1d3b5e-6076-48d4-ac25-6af78653d25c;5;;;;;;;;;;;;|3d1dae40-7b67-4c91-b96b-cd64323e7729;3;0;35.270134;139.529297;0.0;;;138;;;;;|3ffa6395-9c48-4778-8435-23941f1468b5;3;0;35.271402;139.528498;2.1;;;75;;;;;|43c0afca-4541-407e-a838-62b0b9c6107a;5;0;35.243898;139.536739;0.4;;;203;;;;;|4949c1bc-1a64-41e7-aac0-1755e1475654;5;0;35.259178;139.493608;0.4;;;301;;;;;|4fea8d8c-7f82-480c-9be6-54b156835be3;3;57;35.255563;139.48385;0.0;;;141;;;;;|5221ccc9-a2c6-488e-a997-14b3011ea690;5;0;35.270109;139.529213;0.0;;;202;;;;;|5ab4c57a-8f62-49da-98f7-1a3b55d3aef4;3;82;35.287856;139.495553;0.0;;;90;;;;;|5edd2a5c-60dc-452d-8531-351b28c9da47;5;0;35.259076;139.493317;2.7;;;112;;;;;|5f2be0cf-c409-4cd5-8c6f-73ec04c74cec;5;0;35.288788;139.496593;0.4;;;300;;;;;|61510f24-5a80-4495-aade-6e6dfb97cff0;5;618;35.261148;139.494548;1.4;;;226;;;;;|64bc1273-8aab-4ef1-8bf9-748ccc40f2d5;5;0;35.256647;139.519281;1.2;;;68;;;;;|65fa9055-0e4f-406b-8cdb-9da6a31fbfef;5;0;35.287871;139.523833;0.6;;;248;;;;;|66733af1-355b-4b2d-863d-3cbcae89cb22;5;0;35.290807;139.507125;0.4;;;90;;;;;|6a52394f-3f3f-4a36-98ef-bbcdf623c0e1;5;0;35.250647;139.556728;0.4;;;270;;;;;|6ee5589d-79ce-4a39-93fe-6571d68a94fd;5;9042;35.252182;139.546278;11.7;;;130;;;;;|7721940e-6ae6-4157-8c42-8eb22b5ae58f;3;0;35.255564;139.483859;0.2;;;90;;;;;|81de4f19-0e37-419e-82eb-d369a040ee7c;5;0;35.284915;139.516334;0.0;;;90;;;;;|844cc0c6-e73d-41f6-9d80-5151f6878cde;5;0;35.284906;139.516346;0.0;;;270;;;;;|85fadddc-983c-4254-9273-4a1ad73b5731;5;0;35.288784;139.49661;0.4;;;270;;;;;|8b892963-e078-40ff-b6a4-67b87bdc4855;5;0;35.253099;139.51882;0.2;;;360;;;;;|922f94be-7724-4004-9d24-6a5eb7286099;5;83;35.287871;139.524114;0.6;;;238;;;;;|93926478-f928-432c-901d-431003ef0f18;5;0;35.290555;139.517883;0.6;;;270;;;;;|98e428d2-a181-4162-9060-ebdb4313cb2a;5;0;35.28807;139.512915;0.2;;;239;;;;;|9a3298d4-b405-429e-8170-9dacada0bfba;5;0;35.271545;139.529741;0.2;;;360;;;;;|9cc93765-02c2-4f5f-ad9f-14e469d4874d;3;0;35.247147;139.513394;0.0;;;321;;;;;|9d4263f5-52e6-4dcd-94c6-9ae841d06c76;3;0;35.286935;139.511785;0.6;;;270;;;;;|a03b195b-cf20-4e52-8d05-68717adea11e;3;0;35.284925;139.516377;0.0;;;90;;;;;|a3005701-0870-45cc-84db-3b678afc3a23;3;0;35.287403;139.515162;0.0;;;90;;;;;|a3269b48-739c-497e-846a-3be163457320;3;0;35.270132;139.529265;0.0;;;143;;;;;|a46cc3c5-a142-424e-9b0a-e8bdcb82f813;3;0;35.247431;139.5111;0.4;;;339;;;;;|b2ec920a-8192-4c4b-a58c-0b2e43f6e9f4;3;0;35.254888;139.484122;0.2;;;90;;;;;|b55cc804-3a74-4db4-9ed0-b0b2e931b24f;5;0;35.271023;139.530127;0.2;;;90;;;;;|c1515836-34e1-4ba6-b3bd-1edda4659d3b;5;0;35.299634;139.483991;0.0;;;360;;;;;|c4e9491d-aa36-4e20-aacf-9b4cfa3df61d;5;0;35.248233;139.512246;0.6;;;90;;;;;|ca028761-bec6-4513-9f00-e0fef2b3d606;3;273;35.271139;139.528568;0.6;;;321;;;;;|ca84e3c3-b991-4025-a24f-903135d4a7e5;3;0;35.245991;139.548126;2.5;;;222;;;;;|cf5af8a8-fe68-48b8-9dde-29b5ba8dc073;5;0;35.286219;139.517599;0.6;;;292;;;;;|cf76e9a5-8244-41f3-987a-bef529c48a74;5;0;35.250647;139.557105;0.2;;;270;;;;;|d37712aa-62b8-498d-8970-ea9a8e859ab1;3;12;35.285947;139.496245;1.2;;;81;;;;;|d4348384-01fc-40ed-818d-f7375a187e4f;5;0;35.248715;139.511822;0.0;;;244;;;;;|de02144b-771e-49ea-bc2f-f52d3d22a3dd;3;0;35.254877;139.484061;0.2;;;270;;;;;|df78084b-e9bc-475c-a418-48a5cc4d992f;5;0;35.277041;139.540017;0.6;;;143;;;;;|dfa00db0-3fa0-4524-a468-2d9d7b45a150;5;0;35.290436;139.507;0.6;;;22;;;;;|e1dbea90-bc68-4798-b3d6-c7d3bbc8bbd0;3;0;35.241517;139.53718;1.2;;;338;;;;;|e2fab779-542b-43e9-89fe-1481c0475aaa;5;0;35.252376;139.547022;0.6;;;90;;;;;|e4a75785-61c6-4d4f-bf17-45981e82191b;5;0;35.299626;139.483976;0.0;;;90;;;;;|eb9f7c73-b570-4182-b618-a5d134c5082e;3;0;35.286174;139.496824;1.7;;;49;;;;;|f46926c8-5572-4784-83a3-3092ea48730e;5;0;35.29966;139.484017;0.0;;;270;;;;;|f5882727-5f43-4c36-bf60-78ba45cfbe3b;3;0;35.247174;139.513385;0.2;;;338;;;;;|f61891e5-89e5-47eb-bf22-ac469bdd0ede;5;0;35.255676;139.484818;0.4;;;165;;;;;|f6c78cda-d1c1-4add-8d18-b6320be9226f;5;0;35.242038;139.546602;0.4;;;219;;;;;|fb9dcc99-1fb9-4cff-b377-9e9b2ccc4c7a;5;0;35.256585;139.484501;0.6;;;239;;;;;|dc5f272b-c041-4595-8cb9-a9559f551048;1;0;35.27271;139.535808;5.4;3.9;3.2;191;2;4;214;529;|e0d78e51-e427-4751-8663-dbaae6990545;1;0;35.276309;139.533649;5.4;4.7;3.0;206;2;9;281;596;|8f470978-cfdc-4324-83f6-2df14be53090;1;0;35.274263;139.534595;5.4;4.8;3.1;208;2;5;220;535;|e87efa8a-b97b-40eb-8923-46993ae78075;1;0;35.268715;139.540604;5.2;3.4;4.3;185;2;16;401;715;|ffc6c67d-45f5-4f46-9bdb-a49abb873c31;1;0;35.299348;139.484229;0.0;0.0;0.0;39;2;21;3358;3673;|4ed73356-2a9a-4749-a5f9-ef7e5969bc97;1;0;35.271586;139.538937;5.8;3.2;4.0;291;2;14;376;691;|d96f6bf5-5d50-4695-adfd-addbafad6783;1;;;;;;;;;;;;DNC|ceb4f079-d696-4fad-b548-196e8ae42e2b;1;113;35.273095;139.539657;9.1;2.3;0.0;160;2;17;526;841;|52123e7c-6eee-4ca3-bc04-a3291adbb8a2;1;3809;35.277406;139.541492;8.7;;0.0;91;2;;;1251;|c6ee3315-a57b-43fc-addd-3fe38b19f801;1;;;;;;;;;;;;DNC|375cb959-da8a-40a9-8fdd-c2d95f6c026f;1;6949;35.2718;139.542195;6.4;;0.0;95;2;;;948;|a838c98f-6743-4b59-8b03-812c5117090e;1;0;35.299318;139.484233;0.0;0.0;0.0;90;2;18;3356;3671;|31fc4551-b5b0-4181-8df0-52129d2a124d;1;0;35.269058;139.539401;4.1;3.5;3.2;205;2;11;319;634;|f33df1df-7037-4625-8823-234cc1ef5013;1;0;35.272408;139.538294;6.2;2.4;3.7;302;2;15;381;695;|3a317d5d-4a33-4f09-8e7a-dcb4524831f1;1;0;35.273539;139.53592;5.1;2.6;3.0;294;2;8;275;590;|5c122375-4b15-4f82-8cdf-846e24a02ad5;1;0;35.273925;139.533292;5.4;4.9;3.0;210;2;2;102;417;|00774596-7fd5-4170-9e85-16b649b5c120;1;0;35.275801;139.533777;6.2;5.6;3.2;209;2;6;258;573;|d812c7f4-383a-4860-bdd4-4d21c141f3e8;1;0;35.299366;139.484266;0.0;0.0;0.0;119;2;20;3357;3672;|9a8770e5-9c2b-48ad-8510-3aac3f016060;1;0;35.26867;139.539802;4.7;2.7;4.2;180;2;12;352;667;|2c11cbe3-ef91-4daa-b50d-1da68820e450;1;0;35.272456;139.53706;4.7;1.7;3.3;304;2;10;291;606;|8a02c1e8-e1a7-4562-b3d9-baa8c602f319;1;0;35.2729;139.536282;5.8;3.7;3.5;185;2;7;261;576;|316b9ee6-5a6c-4a8d-8bbb-33e6e1123d68;1;0;35.273131;139.532612;5.4;5.1;3.1;213;2;1;0;315;|2210628b-8e79-4059-9afb-3ab937e89f2c;1;0;35.269445;139.540216;4.1;1.9;3.5;173;2;13;362;677;|12fd9883-b95e-4a15-ae66-8994cd487eac;1;0;35.299323;139.484234;0.0;0.0;0.0;222;2;19;3357;3672;|9bcee4ee-9cee-4658-9800-415e1eb6518b;1;0;35.27481;139.533061;5.8;5.5;3.1;215;2;3;142;457;"; + assertRPDMessageCanBeParsed(rpdMessage); + } + + @Test + public void parseRPDWithEmptyStringsMessage() throws InterruptedException, ParseException, UnknownHostException, IOException { + final String rpdMessage = "RPD|005ec96a-9751-45d5-b77a-4ff2db19702f|,|2018-09-14T05:25:27+00:00|||||1|457898af-5af3-441e-9a80-bbc09379855c;;;35.299492;139.484399;0.0;;;33;;;;;"; + assertRPDMessageCanBeParsed(rpdMessage); + } + + private void assertRPDMessageCanBeParsed(final String rpdMessage) + throws InterruptedException, ParseException, IOException { final SailMasterMessage message = new SailMasterMessageImpl(rpdMessage); final SailMasterConnectorImpl connector = new SailMasterConnectorImpl(/* host */ "8.8.8.8", /* port */ 443, /* raceId */ null, /* raceName */ null, /* raceDescription */ null, /* boatClass */ null); final boolean[] receivedPositionData = new boolean[1]; diff --git a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SailMasterConnectorImpl.java b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SailMasterConnectorImpl.java index ba14085368f..dd44a0b5a6e 100755 --- a/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SailMasterConnectorImpl.java +++ b/java/com.sap.sailing.domain.swisstimingadapter/src/com/sap/sailing/domain/swisstimingadapter/impl/SailMasterConnectorImpl.java @@ -361,16 +361,16 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement assert message.getType() == MessageType.RPD; String[] sections = message.getSections(); String raceID = sections[1]; - final RaceStatus raceStatus; - final RacingStatus racingStatus; final String[] raceStatusIntAndRacingStatusInt = sections[2].split(","); + final String raceStatusAsString = raceStatusIntAndRacingStatusInt.length > 0 ? raceStatusIntAndRacingStatusInt[0] : null; + final RaceStatus raceStatus = raceStatusAsString == null || raceStatusAsString.trim().isEmpty() ? null : RaceStatus.values()[Integer.valueOf(raceStatusAsString)]; + final String racingStatusAsString; if (raceStatusIntAndRacingStatusInt.length > 1) { - raceStatus = RaceStatus.values()[Integer.valueOf(raceStatusIntAndRacingStatusInt[0])]; - racingStatus = RacingStatus.values()[Integer.valueOf(raceStatusIntAndRacingStatusInt[1])]; + racingStatusAsString = raceStatusIntAndRacingStatusInt[1]; } else { - raceStatus = RaceStatus.values()[Integer.valueOf(raceStatusIntAndRacingStatusInt[0])]; - racingStatus = null; + racingStatusAsString = null; } + final RacingStatus racingStatus = racingStatusAsString == null || racingStatusAsString.trim().isEmpty() ? null : RacingStatus.values()[Integer.valueOf(racingStatusAsString)]; TimePoint timePoint = new MillisecondsTimePoint(parseTimeAndDateISO(sections[3], raceID)); lastRPDMessageTimePoint = timePoint; String dateISO = sections[3].substring(0, sections[3].indexOf('T')); @@ -392,7 +392,8 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement if (fixSections.length > 2) { final String trackedObjectIdAsString = fixSections[fixDetailIndex++].trim(); if (trackedObjectIdAsString != null && !trackedObjectIdAsString.trim().isEmpty()) { - final TrackerType trackerType = TrackerType.values()[Integer.valueOf(fixSections[fixDetailIndex++])]; + final String trackerTypeAsString = fixSections[fixDetailIndex++]; + final TrackerType trackerType = trackerTypeAsString == null || trackerTypeAsString.trim().isEmpty() ? null : TrackerType.values()[Integer.valueOf(trackerTypeAsString)]; final String ageOfDataInMillisAsString = fixSections[fixDetailIndex++]; final Long ageOfDataInMilliseconds = ageOfDataInMillisAsString==null || ageOfDataInMillisAsString.trim().isEmpty() ? null : (1000l * Long.valueOf(ageOfDataInMillisAsString)); final String latDegAsString = fixSections[fixDetailIndex++]; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/VideoNode.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/VideoNode.java index 164f4b892e5..451b7a29860 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/VideoNode.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/nodes/VideoNode.java @@ -28,7 +28,7 @@ public class VideoNode extends FiresPlaceNode { public void onStart() { EventDTO event = cf.getAutoPlayCtxSignalError().getEvent(); - List videos = event.getVideos().stream().filter(v -> v.hasTag(MediaTagConstants.BIGSCREEN)) + List videos = event.getVideos().stream().filter(v -> v.hasTag(MediaTagConstants.BIGSCREEN.getName())) .collect(Collectors.toList()); if (videos.size() == 0) { lastPlayed = -1; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/screens/idleloop/idleupnext/IdleUpNextPresenterImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/screens/idleloop/idleupnext/IdleUpNextPresenterImpl.java index a0da195dc86..27fe79b860f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/screens/idleloop/idleupnext/IdleUpNextPresenterImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/screens/idleloop/idleupnext/IdleUpNextPresenterImpl.java @@ -80,9 +80,9 @@ public class IdleUpNextPresenterImpl extends AutoPlayPresenterConfigured bigScreenImages = new ArrayList<>(); for (ImageDTO imageDTO : getSlideCtx().getEvent().getImages()) { final List tags = imageDTO.getTags(); - if (tags.contains(MediaTagConstants.BIGSCREEN)) { + if (tags.contains(MediaTagConstants.BIGSCREEN.getName())) { bigScreenImages.add(UriUtils.fromString(imageDTO.getSourceRef())); - } else if (tags.contains(MediaTagConstants.TEASER) || tags.contains(MediaTagConstants.HIGHLIGHT)) { + } else if (tags.contains(MediaTagConstants.TEASER.getName()) || tags.contains(MediaTagConstants.HIGHLIGHT.getName())) { teaserHighlight.add(UriUtils.fromString(imageDTO.getSourceRef())); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/screens/preevent/IdlePreEventPresenterImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/screens/preevent/IdlePreEventPresenterImpl.java index e0073c7b3fd..001bba5a0be 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/screens/preevent/IdlePreEventPresenterImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/places/screens/preevent/IdlePreEventPresenterImpl.java @@ -84,11 +84,11 @@ public class IdlePreEventPresenterImpl extends AutoPlayPresenterConfigured teaserHighlight = new ArrayList<>(); List bigScreenImages = new ArrayList<>(); for (ImageDTO imageDTO : getSlideCtx().getEvent().getImages()) { - if (imageDTO.getTags().contains(MediaTagConstants.BIGSCREEN)) { + if (imageDTO.getTags().contains(MediaTagConstants.BIGSCREEN.getName())) { bigScreenImages.add(imageDTO); - } else if (imageDTO.getTags().contains(MediaTagConstants.TEASER)) { + } else if (imageDTO.getTags().contains(MediaTagConstants.TEASER.getName())) { teaserHighlight.add(imageDTO); - } else if (imageDTO.getTags().contains(MediaTagConstants.HIGHLIGHT)) { + } else if (imageDTO.getTags().contains(MediaTagConstants.HIGHLIGHT.getName())) { teaserHighlight.add(imageDTO); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/GetEventViewAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/GetEventViewAction.java index 264c9861ec1..31c46e1b8fd 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/GetEventViewAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/GetEventViewAction.java @@ -58,7 +58,7 @@ public class GetEventViewAction implements SailingAction, IsClient final EventViewDTO dto = new EventViewDTO(); HomeServiceUtil.mapToMetadataDTO(event, dto, context.getRacingEventService()); - ImageDescriptor logoImage = event.findImageWithTag(MediaTagConstants.LOGO); + ImageDescriptor logoImage = event.findImageWithTag(MediaTagConstants.LOGO.getName()); dto.setLogoImage(logoImage != null ? HomeServiceUtil.convertToImageDTO(logoImage) : null); dto.setOfficialWebsiteURL(event.getOfficialWebsiteURL() == null ? null : event.getOfficialWebsiteURL().toString()); URL sailorsInfoWebsiteURL = event.getSailorsInfoWebsiteURLOrFallback(context.getClientLocale()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/eventoverview/GetEventOverviewStageAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/eventoverview/GetEventOverviewStageAction.java index f6e67d6fc3d..ca953a0f1ea 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/eventoverview/GetEventOverviewStageAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/eventoverview/GetEventOverviewStageAction.java @@ -79,7 +79,7 @@ public class GetEventOverviewStageAction implements SailingAction videoTags = Collections.singletonList(MediaTagConstants.FEATURED); + List videoTags = Collections.singletonList(MediaTagConstants.FEATURED.getName()); VideoDescriptor featuredVideo = HomeServiceUtil.getStageVideo(event, context.getClientLocale(), videoTags , false); if (featuredVideo != null) { return new EventOverviewVideoStageDTO(EventOverviewVideoStageDTO.Type.MEDIA, diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/fakeseries/GetEventSeriesViewAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/fakeseries/GetEventSeriesViewAction.java index 902cacb2e7d..2e99568b932 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/fakeseries/GetEventSeriesViewAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/fakeseries/GetEventSeriesViewAction.java @@ -51,7 +51,7 @@ public class GetEventSeriesViewAction implements SailingAction, IsClient } for (VideoDescriptor video : event.getVideos()) { MimeType type = video.getMimeType(); - if (MediaConstants.SUPPORTED_VIDEO_TYPES.contains(type)) { + if (MediaTagConstants.SUPPORTED_VIDEO_TYPES.contains(type)) { SailingVideoDTO videoDTO = HomeServiceUtil.toSailingVideoDTO(eventRef, video); media.addVideo(videoDTO); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/media/SailingImageDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/media/SailingImageDTO.java index 86d817e109b..f88c1d5ebbb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/media/SailingImageDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/media/SailingImageDTO.java @@ -10,8 +10,8 @@ public class SailingImageDTO extends ImageDTO { private EventLinkDTO eventLink; + @Deprecated protected SailingImageDTO() { - super(); } public SailingImageDTO(EventLinkDTO eventLink, String imageRef, Date createdAtDate) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/media/SailingVideoDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/media/SailingVideoDTO.java index 490f07fd631..72dc0ef866e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/media/SailingVideoDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/media/SailingVideoDTO.java @@ -12,6 +12,7 @@ public class SailingVideoDTO extends VideoDTO { private EventReferenceDTO eventRef; /** for GWT */ + @Deprecated protected SailingVideoDTO() { } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/start/GetStartViewAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/start/GetStartViewAction.java index c4c1f54e3c8..708ba2ded62 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/start/GetStartViewAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/start/GetStartViewAction.java @@ -19,9 +19,9 @@ import com.sap.sailing.gwt.server.EventHolder; import com.sap.sailing.gwt.server.EventStageCandidateCalculator; import com.sap.sailing.gwt.server.HomeServiceUtil; import com.sap.sailing.gwt.server.RecentEventsCalculator; -import com.sap.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; +import com.sap.sse.common.media.MediaTagConstants; import com.sap.sse.common.media.MimeType; import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable; import com.sap.sse.shared.media.ImageDescriptor; @@ -63,7 +63,7 @@ public class GetStartViewAction implements SailingAction, IsClient if (!Util.isEmpty(videosOfEvent) && result.getVideos().size() < MAX_VIDEO_COUNT) { VideoDescriptor youTubeRandomUrl = HomeServiceUtil.getRandomVideo(videosOfEvent); MimeType type = youTubeRandomUrl.getMimeType(); - if (MediaConstants.SUPPORTED_VIDEO_TYPES.contains(type)) { + if (MediaTagConstants.SUPPORTED_VIDEO_TYPES.contains(type)) { SailingVideoDTO candidate = new SailingVideoDTO(eventRef, youTubeRandomUrl.getURL().toString(), type, youTubeRandomUrl.getCreatedAtDate().asDate()); candidate.setTitle(holder.event.getName()); @@ -91,7 +91,7 @@ public class GetStartViewAction implements SailingAction, IsClient } for (VideoDescriptor videoUrl : event.getVideos()) { MimeType type = videoUrl.getMimeType(); - if (MediaConstants.SUPPORTED_VIDEO_TYPES.contains(type)) { + if (MediaTagConstants.SUPPORTED_VIDEO_TYPES.contains(type)) { SailingVideoDTO candidate = new SailingVideoDTO(eventRef, videoUrl.getURL().toString(), type, // videoUrl.getCreatedAtDate().asDate() ); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java index d230ac96718..c8ab8e05ad0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java @@ -38,7 +38,6 @@ import com.sap.sailing.gwt.home.communication.eventlist.EventListEventDTO; import com.sap.sailing.gwt.home.communication.media.SailingVideoDTO; import com.sap.sailing.gwt.home.communication.start.EventStageDTO; import com.sap.sailing.gwt.home.communication.start.StageEventType; -import com.sap.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.util.EventUtil; import com.sap.sse.common.TimePoint; @@ -123,11 +122,11 @@ public final class HomeServiceUtil { } private static ImageDescriptor findEventThumbnailImage(EventBase event) { - return event.findImageWithTag(MediaTagConstants.TEASER); + return event.findImageWithTag(MediaTagConstants.TEASER.getName()); } public static ImageDescriptor getFeaturedImage(EventBase event) { - return event.findImageWithTag(MediaTagConstants.FEATURED); + return event.findImageWithTag(MediaTagConstants.FEATURED.getName()); } public static String getFeaturedImageUrlAsString(EventBase event) { @@ -141,7 +140,7 @@ public final class HomeServiceUtil { } public static ImageDescriptor getStageImage(final EventBase event) { - return event.findImageWithTag(MediaTagConstants.STAGE); + return event.findImageWithTag(MediaTagConstants.STAGE.getName()); } public static List getPhotoGalleryImageURLsAsString(EventBase event) { @@ -154,14 +153,14 @@ public final class HomeServiceUtil { } public static List getPhotoGalleryImages(EventBase event) { - return event.findImagesWithTag(MediaTagConstants.GALLERY); + return event.findImagesWithTag(MediaTagConstants.GALLERY.getName()); } public static List getSailingLovesPhotographyImages(EventBase event) { final List acceptedImages = new LinkedList<>(); for (ImageDescriptor candidateImageUrl : event.getImages()) { if (candidateImageUrl.hasSize() && candidateImageUrl.getHeightInPx() > MINIMUM_IMAGE_HEIGHT_FOR_SAILING_PHOTOGRAPHY_IN_PIXELS) { - if (candidateImageUrl.hasTag(MediaTagConstants.STAGE) || candidateImageUrl.hasTag(MediaTagConstants.GALLERY)) { + if (candidateImageUrl.hasTag(MediaTagConstants.STAGE.getName()) || candidateImageUrl.hasTag(MediaTagConstants.GALLERY.getName())) { acceptedImages.add(candidateImageUrl); } } @@ -201,7 +200,7 @@ public final class HomeServiceUtil { } public static boolean hasPhotos(Event event) { - return event.hasImageWithTag(MediaTagConstants.GALLERY); + return event.hasImageWithTag(MediaTagConstants.GALLERY.getName()); } public static boolean hasVideos(Event event) { @@ -229,7 +228,7 @@ public final class HomeServiceUtil { VideoDescriptor bestMatch = null; for (VideoDescriptor videoCandidate : event.getVideos()) { - if(!MediaConstants.SUPPORTED_VIDEO_TYPES.contains(videoCandidate.getMimeType())) { + if(!MediaTagConstants.SUPPORTED_VIDEO_TYPES.contains(videoCandidate.getMimeType())) { continue; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index cbf77d1c367..969d5285606 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -12,6 +12,8 @@ import java.util.UUID; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.i18n.client.LocaleInfo; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FocusWidget; import com.google.gwt.user.client.ui.Grid; @@ -37,8 +39,10 @@ import com.sap.sse.gwt.client.controls.listedit.GenericStringListEditorComposite import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite; import com.sap.sse.gwt.client.controls.listedit.StringConstantsListEditorComposite; import com.sap.sse.gwt.client.controls.listedit.StringListInlineEditorComposite; +import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtServiceAsync; import com.sap.sse.gwt.client.media.ImageDTO; import com.sap.sse.gwt.client.media.VideoDTO; +import com.sap.sse.gwt.shared.filestorage.FileStorageServicePropertyErrorsDTO; public abstract class EventDialog extends DataEntryDialogWithDateTimeBox { protected StringMessages stringMessages; @@ -57,6 +61,7 @@ public abstract class EventDialog extends DataEntryDialogWithDateTimeBox { @@ -129,6 +134,7 @@ public abstract class EventDialog extends DataEntryDialogWithDateTimeBox availableLeaderboardGroups, Iterable leaderboardGroupsOfEvent, DialogCallback callback) { super(stringMessages.event(), null, stringMessages.ok(), stringMessages.cancel(), validator, callback); + testFileStorageService(sailingService); this.stringMessages = stringMessages; this.availableLeaderboardGroupsByName = new HashMap<>(); for (final LeaderboardGroupDTO lgDTO : availableLeaderboardGroups) { @@ -159,8 +165,8 @@ public abstract class EventDialog extends DataEntryDialogWithDateTimeBox suggestedWindFinderSpotCollections = AvailableWindFinderSpotCollections .getAllAvailableWindFinderSpotCollectionsInAlphabeticalOrder() == null ? Collections.emptyList() @@ -261,4 +267,73 @@ public abstract class EventDialog extends DataEntryDialogWithDateTimeBox() { + + @Override + public void onFailure(Throwable caught) { + } + + @Override + public void onSuccess(FileStorageServicePropertyErrorsDTO result) { + if (result == null) { + storageServiceAvailable.testPassed(); + } + } + }); + } + + /** + * The only purpose of this class is to hold the value of the response of the {@link EventDialog#testFileStorageService(FileStorageManagementGwtServiceAsync)} method + * It will notify all registered observers on a change and directly after the registration, if the value is already true + * The value of this will only change from false to true, so the value can also be seen as an alreadyChanged value + * If the test fails, the value will not change due its lifetime + * + * @author Robin Fleige (D067799) + */ + public class FileStorageServiceConnectionTestObservable { + private List observer = new ArrayList<>(); + private boolean value; + + public FileStorageServiceConnectionTestObservable() { + value = false; + } + + public void testPassed() { + value = true; + for (FileStorageServiceConnectionTestObserver observer : this.observer) { + observer.onFileStorageServiceTestPassed(); + } + } + + public boolean getValue() { + return value; + } + + public void registerObserver(FileStorageServiceConnectionTestObserver observer) { + this.observer.add(observer); + if (value) { + observer.onFileStorageServiceTestPassed(); + } + } + + public void unregisterObserver(FileStorageServiceConnectionTestObserver observer) { + this.observer.remove(observer); + } + } + + /** + * The only use of this interface is to get notified if the response of the {@link EventDialog#testFileStorageService(FileStorageManagementGwtServiceAsync)} method arrives + * Also see {@link EventDialog.FileStorageServiceConnectionTestObservable} + * + * @author Robin Fleige (D067799) + */ + public interface FileStorageServiceConnectionTestObserver { + void onFileStorageServiceTestPassed(); + } + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java index 141a3f74a45..e80956c6646 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageCreateDialog.java @@ -5,14 +5,15 @@ import java.util.Date; import java.util.List; import com.google.gwt.user.client.ui.Label; +import com.sap.sailing.gwt.ui.adminconsole.EventDialog.FileStorageServiceConnectionTestObservable; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sse.gwt.client.media.ImageDTO; +import com.sap.sse.gwt.client.media.ImageResizingTaskDTO; public class ImageCreateDialog extends ImageDialog { - public ImageCreateDialog(String initialTag, SailingServiceAsync sailingService, StringMessages stringMessages, DialogCallback callback) { - super(new Date(), new ImageParameterValidator(stringMessages), sailingService, stringMessages, callback); + public ImageCreateDialog(String initialTag, SailingServiceAsync sailingService, StringMessages stringMessages, FileStorageServiceConnectionTestObservable storageServiceAvailable, DialogCallback dialogCallback) { + super(new Date(), sailingService, stringMessages, storageServiceAvailable, dialogCallback); createdAtLabel = new Label(creationDate.toString()); titleTextBox = createTextBox(null); titleTextBox.setVisibleLength(40); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java index 0bd7c3f1d6b..4f8f7f972aa 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java @@ -1,13 +1,17 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FocusWidget; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.HTML; @@ -16,9 +20,11 @@ import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.ui.adminconsole.EventDialog.FileStorageServiceConnectionTestObservable; +import com.sap.sailing.gwt.ui.adminconsole.EventDialog.FileStorageServiceConnectionTestObserver; +import com.sap.sailing.gwt.ui.client.SailingService; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; import com.sap.sse.common.media.MediaTagConstants; @@ -27,12 +33,14 @@ import com.sap.sse.gwt.client.IconResources; import com.sap.sse.gwt.client.controls.IntegerBox; import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator; import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator; -import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite; +import com.sap.sse.gwt.client.controls.listedit.ExpandedUiWithCheckboxes; import com.sap.sse.gwt.client.controls.listedit.StringListInlineEditorComposite; import com.sap.sse.gwt.client.dialog.DataEntryDialog; import com.sap.sse.gwt.client.media.ImageDTO; +import com.sap.sse.gwt.client.media.ImageResizingTaskDTO; -public abstract class ImageDialog extends DataEntryDialog { +public abstract class ImageDialog extends DataEntryDialog + implements FileStorageServiceConnectionTestObserver { private final SailingServiceAsync sailingService; protected final StringMessages stringMessages; @@ -44,70 +52,165 @@ public abstract class ImageDialog extends DataEntryDialog { protected TextBox copyrightTextBox; protected IntegerBox widthInPxBox; protected IntegerBox heightInPxBox; - protected StringListInlineEditorComposite tagsListEditor; + protected final StringListInlineEditorComposite tagsListEditor; protected Image image; + private final ExpandedUiWithCheckboxes expandedUi; private final BusyIndicator busyIndicator; - protected static class ImageParameterValidator implements Validator { - private StringMessages stringMessages; + protected static class ImageParameterValidator implements Validator { + private final StringMessages stringMessages; + private List doResize; + private final FileStorageServiceConnectionTestObservable storageServiceAvailable; - public ImageParameterValidator(StringMessages stringMessages) { + public ImageParameterValidator(StringMessages stringMessages, + FileStorageServiceConnectionTestObservable storageServiceAvailable) { this.stringMessages = stringMessages; + this.storageServiceAvailable = storageServiceAvailable; + this.doResize = new ArrayList(); + } + + public void setCheckBoxes(List doResize) { + this.doResize = doResize; } + /* + * author Robin Fleige (D067799) + * will return an error message if the image is too small + * will return an error message if the width-height-ratio is not fitting for a resize + * will return an error message and show a checkbox to allow resizing if the image is too big + * will disable the checkbox if there is no working FileStorageService + */ @Override - public String getErrorMessage(ImageDTO imageToValidate) { + public String getErrorMessage(final ImageResizingTaskDTO resizingTask) { String errorMessage = null; - Integer imageWidth = imageToValidate.getWidthInPx(); - Integer imageHeight = imageToValidate.getHeightInPx(); - + final ImageDTO imageToValidate = resizingTask.getImage(); + final Integer imageWidth = imageToValidate.getWidthInPx(); + final Integer imageHeight = imageToValidate.getHeightInPx(); + if (imageToValidate.getSourceRef() == null || imageToValidate.getSourceRef().isEmpty()) { - errorMessage = stringMessages.pleaseEnterNonEmptyUrl(); + errorMessage = stringMessages.pleaseEnterNonEmptyUrlOrUploadImage(); } else if (imageWidth == null || imageHeight == null) { errorMessage = stringMessages.couldNotRetrieveImageSizeYet(); - } else if (imageToValidate.hasTag(MediaTagConstants.LOGO) - && !isValidSize(imageWidth, imageHeight, MediaConstants.MIN_LOGO_IMAGE_WIDTH, - MediaConstants.MAX_LOGO_IMAGE_WIDTH, MediaConstants.MIN_LOGO_IMAGE_HEIGHT, - MediaConstants.MAX_LOGO_IMAGE_HEIGHT)) { - errorMessage = getSizeErrorMessage("Logo", MediaConstants.MIN_LOGO_IMAGE_WIDTH, - MediaConstants.MAX_LOGO_IMAGE_WIDTH, MediaConstants.MIN_LOGO_IMAGE_HEIGHT, - MediaConstants.MAX_LOGO_IMAGE_HEIGHT, stringMessages); - } else if (imageToValidate.hasTag(MediaTagConstants.TEASER) - && !isValidSize(imageWidth, imageHeight, MediaConstants.MIN_EVENTTEASER_IMAGE_WIDTH, - MediaConstants.MAX_EVENTTEASER_IMAGE_WIDTH, MediaConstants.MIN_EVENTTEASER_IMAGE_HEIGHT, - MediaConstants.MAX_EVENTTEASER_IMAGE_HEIGHT)) { - errorMessage = getSizeErrorMessage("Event-Teaser", MediaConstants.MIN_EVENTTEASER_IMAGE_WIDTH, - MediaConstants.MAX_EVENTTEASER_IMAGE_WIDTH, MediaConstants.MIN_EVENTTEASER_IMAGE_HEIGHT, - MediaConstants.MAX_EVENTTEASER_IMAGE_HEIGHT, stringMessages); - } else if (imageToValidate.hasTag(MediaTagConstants.STAGE) - && !isValidSize(imageWidth, imageHeight, MediaConstants.MIN_STAGE_IMAGE_WIDTH, - MediaConstants.MAX_STAGE_IMAGE_WIDTH, MediaConstants.MIN_STAGE_IMAGE_HEIGHT, - MediaConstants.MAX_STAGE_IMAGE_HEIGHT)) { - errorMessage = getSizeErrorMessage("Stage", MediaConstants.MIN_STAGE_IMAGE_WIDTH, - MediaConstants.MAX_STAGE_IMAGE_WIDTH, MediaConstants.MIN_STAGE_IMAGE_HEIGHT, - MediaConstants.MAX_STAGE_IMAGE_HEIGHT, stringMessages); + } else { + // check if image is too small for resizing + errorMessage = ""; + for (MediaTagConstants mediaTag : MediaTagConstants.values()) { + if (imageToValidate.hasTag(mediaTag.getName()) + && (imageWidth < mediaTag.getMinWidth() || imageHeight < mediaTag.getMinHeight())) { + errorMessage += getImageToSmallErrorMessage(mediaTag, stringMessages) + "\n"; + } + } + if (errorMessage.equals("")) {// Check if image ratio fits for resizing + errorMessage = imageRatioFits(imageToValidate); + } + if (errorMessage.equals("")) {// check for checkboxes and resizing + for (MediaTagConstants mediaTag : MediaTagConstants.values()) { + final CheckBox checkBox = getCheckBoxForTag(mediaTag.getName(), imageToValidate); + if (imageToValidate.hasTag(mediaTag.getName()) + && (imageWidth > mediaTag.getMaxWidth() || imageHeight > mediaTag.getMaxHeight())) { + if (!resizingTask.getResizingTask().contains(mediaTag)) { + errorMessage += getSizeErrorMessage(mediaTag, stringMessages) + "\n"; + checkBox.setStyleName(ExpandedUiWithCheckboxes.getErrorStyle()); + if (!errorMessage.equals("") && !storageServiceAvailable.getValue()) { + checkBox.setEnabled(false); + } + } else { + checkBox.setStyleName(ExpandedUiWithCheckboxes.getNormalStyle()); + } + } else { + checkBox.setStyleName(ExpandedUiWithCheckboxes.getInvisibleStyle()); + checkBox.setValue(false); + } + } + } + if (!errorMessage.equals("") && !storageServiceAvailable.getValue()) { + errorMessage += stringMessages.automaticResizeNeedsStorageService() + "\n"; + } + } + if (errorMessage.equals("")) { + errorMessage = null; + } + return errorMessage; + } + + /** + * Searches for the checkbox for the given tag and returns it + * + * @author Robin Fleige (D067799) + * + * @param tag + * the tag, the checkbox for is needed + * @param imageToValidate + * the image with a list of all tags + * @returns the fitting checkbox for the tag + */ + private CheckBox getCheckBoxForTag(final String tag, final ImageDTO imageToValidate) { + final List tags = imageToValidate.getTags(); + CheckBox toReturn = null; + for (int i = 0; i < tags.size(); i++) { + if (tags.get(i).equals(tag)) { + toReturn = doResize.get(i); + } + } + return toReturn == null ? new CheckBox() : toReturn; + // new checkbox instead of null, so there is no need for a null check. this will be deleted from garbage + // collector anyway + } + + /** + * Calculates if + * + * @author Robin Fleige (D067799) + * + * @param imageToValidate + * the image which has to be validated + * @returns true if the imageRatio fits into the bounds of all its {@link MediaTagConstants} + */ + private String imageRatioFits(ImageDTO imageToValidate) { + String errorMessage = ""; + final double ratio = ((double) imageToValidate.getWidthInPx()) / imageToValidate.getHeightInPx(); + for (MediaTagConstants mediaTag : MediaTagConstants.values()) { + if (imageToValidate.hasTag(mediaTag.getName())) { + final double minRatio = ((double) mediaTag.getMaxWidth()) / mediaTag.getMinHeight(); + final double maxRatio = ((double) mediaTag.getMinWidth()) / mediaTag.getMaxHeight(); + if (minRatio < ratio || maxRatio > ratio) { + errorMessage += stringMessages.imageResizeError(mediaTag.getName(), minRatio, maxRatio, ratio); + } + } } return errorMessage; } - private boolean isValidSize(int width, int height, int minWidth, int maxWidth, int minHeight, int maxHeight) { - return width >= minWidth && width <= maxWidth && height >= minHeight && height <= maxHeight; + private String getSizeErrorMessage(MediaTagConstants mediaTag, StringMessages stringMessages) { + String errorMessage = stringMessages.imageSizeError(mediaTag.getName(), mediaTag.getMinWidth(), + mediaTag.getMaxWidth(), mediaTag.getMinHeight(), mediaTag.getMaxHeight()); + return errorMessage; } - private String getSizeErrorMessage(String imageType, int minWidth, int maxWidth, int minHeight, int maxHeight, StringMessages stringMessages) { - String errorMessage = stringMessages.imageSizeError(imageType, minWidth, maxWidth, minHeight, maxHeight); + private String getImageToSmallErrorMessage(MediaTagConstants mediaTag, StringMessages stringMessages) { + String errorMessage = stringMessages.imageToSmallError(mediaTag.getName(), mediaTag.getMinWidth(), + mediaTag.getMinHeight()); return errorMessage; } } - public ImageDialog(Date creationDate, ImageParameterValidator validator, SailingServiceAsync sailingService, StringMessages stringMessages, DialogCallback callback) { + public ImageDialog(Date creationDate, SailingServiceAsync sailingService, StringMessages stringMessages, + FileStorageServiceConnectionTestObservable storageServiceAvailable, + DialogCallback callback) { + this(creationDate, sailingService, stringMessages, storageServiceAvailable, + new ImageParameterValidator(stringMessages, storageServiceAvailable), callback); + } + + private ImageDialog(Date creationDate, SailingServiceAsync sailingService, StringMessages stringMessages, + FileStorageServiceConnectionTestObservable storageServiceAvailable, ImageParameterValidator validator, + DialogCallback callback) { super(stringMessages.image(), null, stringMessages.ok(), stringMessages.cancel(), validator, callback); - this.sailingService = sailingService; this.stringMessages = stringMessages; + this.sailingService = sailingService; this.creationDate = creationDate; getDialogBox().getWidget().setWidth("730px"); busyIndicator = new SimpleBusyIndicator(); - imageURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); + imageURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages, false); imageURLAndUploadComposite.addValueChangeHandler(new ValueChangeHandler() { @Override public void onValueChange(ValueChangeEvent event) { @@ -138,10 +241,19 @@ public abstract class ImageDialog extends DataEntryDialog { validateAndUpdate(); } }); - - tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), - new GenericStringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ - MediaConstants.imageTagSuggestions, stringMessages.enterTagsForTheImage(), 30)); + //the observer has to be registered after creating the URLFieldWithFileUpload + storageServiceAvailable.registerObserver(this); + expandedUi = new ExpandedUiWithCheckboxes(stringMessages, IconResources.INSTANCE.removeIcon(), + /* suggestValues */ MediaTagConstants.imageTagSuggestions, stringMessages.enterTagsForTheImage(), 30, + stringMessages.allowResizing()); + expandedUi.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + validateAndUpdate(); + } + }); + validator.setCheckBoxes(expandedUi.getCheckBoxes()); + tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), expandedUi); tagsListEditor.addValueChangeHandler(new ValueChangeHandler>() { @Override public void onValueChange(ValueChangeEvent> event) { @@ -150,21 +262,34 @@ public abstract class ImageDialog extends DataEntryDialog { }); } + /** + * Creates a {@link ImageResizingTaskDTO} which contains an {@link MediaTagConstants} for every tag that does not fit to the boundaries of the image. + * All tags that do not imply a resize will stay together on a single {@link ImageDTO} and are not stored in the {@link ImageResizingTaskDTO}. + * There will be a {@link ImageDTO} for each of the other {@link MediaTagConstants}. + * For a lookout to further progressing see {@link SailingService#resizeImage(ImageResizingTaskDTO)} + */ @Override - protected ImageDTO getResult() { - ImageDTO result = new ImageDTO(imageURLAndUploadComposite.getURL(), creationDate); - result.setTitle(titleTextBox.getValue()); - result.setSubtitle(subtitleTextBox.getValue()); - result.setCopyright(copyrightTextBox.getValue()); - if (widthInPxBox.getValue() != null && heightInPxBox.getValue() != null) { - result.setSizeInPx(widthInPxBox.getValue(), heightInPxBox.getValue()); - } - List tags = new ArrayList(); - for (String tag: tagsListEditor.getValue()) { + protected ImageResizingTaskDTO getResult() { + final List tags = new ArrayList(); + for (String tag : tagsListEditor.getValue()) { tags.add(tag); } - result.setTags(tags); - return result; + final List resizingTask = new ArrayList(); + for (int i = 0; i < tags.size(); i++) { + if (Arrays.asList(MediaTagConstants.values()).contains(MediaTagConstants.fromName(tags.get(i))) + && expandedUi.getCheckBoxes().get(i).getValue()) { + resizingTask.add(MediaTagConstants.fromName(tags.get(i))); + } + } + final ImageDTO image = new ImageDTO(imageURLAndUploadComposite.getURL(), creationDate); + image.setTitle(titleTextBox.getValue()); + image.setSubtitle(subtitleTextBox.getValue()); + image.setCopyright(copyrightTextBox.getValue()); + if (widthInPxBox.getValue() != null && heightInPxBox.getValue() != null) { + image.setSizeInPx(widthInPxBox.getValue(), heightInPxBox.getValue()); + } + image.setTags(tags); + return new ImageResizingTaskDTO(image, resizingTask); } @Override @@ -210,4 +335,9 @@ public abstract class ImageDialog extends DataEntryDialog { protected FocusWidget getInitialFocusWidget() { return imageURLAndUploadComposite.getInitialFocusWidget(); } + + @Override + public void onFileStorageServiceTestPassed() { + imageURLAndUploadComposite.setUploadEnabled(true); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageEditDialog.java index 01929a2bb83..1a097b39c0f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageEditDialog.java @@ -4,13 +4,15 @@ import java.util.ArrayList; import java.util.List; import com.google.gwt.user.client.ui.Label; +import com.sap.sailing.gwt.ui.adminconsole.EventDialog.FileStorageServiceConnectionTestObservable; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.gwt.client.media.ImageDTO; +import com.sap.sse.gwt.client.media.ImageResizingTaskDTO; public class ImageEditDialog extends ImageDialog { - public ImageEditDialog(ImageDTO imageDTO, SailingServiceAsync sailingService, StringMessages stringMessages, DialogCallback callback) { - super(imageDTO.getCreatedAtDate(), new ImageParameterValidator(stringMessages), sailingService, stringMessages, callback); + public ImageEditDialog(ImageDTO imageDTO, SailingServiceAsync sailingService, StringMessages stringMessages, FileStorageServiceConnectionTestObservable storageServiceAvailable, DialogCallback dialogCallback) { + super(imageDTO.getCreatedAtDate(), sailingService, stringMessages, storageServiceAvailable, dialogCallback); createdAtLabel = new Label(imageDTO.getCreatedAtDate().toString()); imageURLAndUploadComposite.setURL(imageDTO.getSourceRef()); titleTextBox = createTextBox(imageDTO.getTitle()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java old mode 100644 new mode 100755 index 8ec8e773206..55b83eccc91 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.Comparator; import java.util.List; +import java.util.Set; import com.google.gwt.cell.client.AbstractCell; import com.google.gwt.cell.client.FieldUpdater; @@ -18,6 +19,7 @@ import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; import com.google.gwt.user.cellview.client.TextColumn; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HorizontalPanel; @@ -27,19 +29,23 @@ import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.view.client.ListDataProvider; import com.google.gwt.view.client.SelectionChangeEvent; import com.google.gwt.view.client.SingleSelectionModel; +import com.sap.sailing.gwt.ui.adminconsole.EventDialog.FileStorageServiceConnectionTestObservable; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil; import com.sap.sse.common.media.MediaTagConstants; import com.sap.sse.common.util.NaturalComparator; import com.sap.sse.gwt.adminconsole.AdminConsoleTableResources; +import com.sap.sse.gwt.client.Notification; +import com.sap.sse.gwt.client.Notification.NotificationType; import com.sap.sse.gwt.client.celltable.BaseCelltable; import com.sap.sse.gwt.client.celltable.ImagesBarColumn; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; import com.sap.sse.gwt.client.media.ImageDTO; +import com.sap.sse.gwt.client.media.ImageResizingTaskDTO; /** - * /** A composite showing the list of media images + * A composite showing the list of media images * * @author Frank Mittag (C5163974) */ @@ -51,6 +57,7 @@ public class ImagesListComposite extends Composite { private SingleSelectionModel imageSelectionModel; private ListDataProvider imageListDataProvider; private final Label noImagesLabel; + private final FileStorageServiceConnectionTestObservable storageServiceAvailable; private final SimplePanel mainPanel; private final VerticalPanel panel; @@ -71,10 +78,11 @@ public class ImagesListComposite extends Composite { private final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class); - public ImagesListComposite(SailingServiceAsync sailingService, final StringMessages stringMessages) { + public ImagesListComposite(final SailingServiceAsync sailingService, final StringMessages stringMessages, + final FileStorageServiceConnectionTestObservable storageServiceAvailable) { this.sailingService = sailingService; this.stringMessages = stringMessages; - + this.storageServiceAvailable = storageServiceAvailable; mainPanel = new SimplePanel(); panel = new VerticalPanel(); mainPanel.setWidget(panel); @@ -87,7 +95,7 @@ public class ImagesListComposite extends Composite { addPhotoBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openCreateImageDialog(MediaTagConstants.GALLERY); + openCreateImageDialog(MediaTagConstants.GALLERY.getName()); } }); imagesControlsPanel.add(addPhotoBtn); @@ -96,7 +104,7 @@ public class ImagesListComposite extends Composite { addStateImageBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openCreateImageDialog(MediaTagConstants.STAGE); + openCreateImageDialog(MediaTagConstants.STAGE.getName()); } }); imagesControlsPanel.add(addStateImageBtn); @@ -105,7 +113,7 @@ public class ImagesListComposite extends Composite { addEventTeaseImageBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openCreateImageDialog(MediaTagConstants.TEASER); + openCreateImageDialog(MediaTagConstants.TEASER.getName()); } }); imagesControlsPanel.add(addEventTeaseImageBtn); @@ -114,7 +122,7 @@ public class ImagesListComposite extends Composite { addLogoImageBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openCreateImageDialog(MediaTagConstants.LOGO); + openCreateImageDialog(MediaTagConstants.LOGO.getName()); } }); imagesControlsPanel.add(addLogoImageBtn); @@ -267,34 +275,74 @@ public class ImagesListComposite extends Composite { } private void openCreateImageDialog(String initialTag) { - ImageCreateDialog dialog = new ImageCreateDialog(initialTag, sailingService, stringMessages, new DialogCallback() { - @Override - public void cancel() { - } + ImageCreateDialog dialog = new ImageCreateDialog(initialTag, sailingService, stringMessages, + storageServiceAvailable, new DialogCallback() { + @Override + public void cancel() { + } - @Override - public void ok(ImageDTO newImage) { - imageListDataProvider.getList().add(newImage); - updateTableVisisbilty(); - } - }); + @Override + public void ok(ImageResizingTaskDTO resizingTask) { + if (resizingTask.getResizingTask().size() != 0) { + callResizingServiceAndUpdateTable(resizingTask, null); + } else { + imageListDataProvider.getList().add(resizingTask.getImage()); + } + } + }); dialog.show(); } private void openEditImageDialog(final ImageDTO selectedImage) { - ImageEditDialog dialog = new ImageEditDialog(selectedImage, sailingService, stringMessages, new DialogCallback() { + ImageEditDialog dialog = new ImageEditDialog(selectedImage, sailingService, stringMessages, + storageServiceAvailable, new DialogCallback() { + @Override + public void cancel() { + } + + @Override + public void ok(ImageResizingTaskDTO resizingTask) { + if (resizingTask.getResizingTask().size() != 0) { + callResizingServiceAndUpdateTable(resizingTask, selectedImage); + } else { + imageListDataProvider.getList().remove(selectedImage); + imageListDataProvider.getList().add(resizingTask.getImage()); + } + } + }); + dialog.show(); + } + + /** + * Calls the resizing service and updates the imageListDataProvider with the returned ImageDTOs + * + * @author Robin Fleige (D067799) + * + * @param resizingTask + * The {@link ImageResizingTaskDTO} that contains the information about resizing. The resizingTask + * attribute should not be null or empty at this point. + * @param originalImage + * if called from {@link ImageEditDialog} contains the selected image, that will be replaced by the + * returned ImageDTOs + */ + protected void callResizingServiceAndUpdateTable(ImageResizingTaskDTO resizingTask, ImageDTO originalImage) { + sailingService.resizeImage(resizingTask, new AsyncCallback>() { @Override - public void cancel() { + public void onFailure(Throwable caught) { + Notification.notify(stringMessages.resizeUnsuccessfull(), NotificationType.ERROR); } @Override - public void ok(ImageDTO updatedImage) { - imageListDataProvider.getList().remove(selectedImage); - imageListDataProvider.getList().add(updatedImage); + public void onSuccess(Set result) { + for (ImageDTO image : result) { + imageListDataProvider.getList().add(image); + } + imageListDataProvider.getList().remove(originalImage); updateTableVisisbilty(); + Notification.notify(stringMessages.resizeSuccessfull(), NotificationType.SUCCESS); } }); - dialog.show(); + } private void updateTableVisisbilty() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java index a4980fd043e..d26e3d8fb57 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SeriesEditDialog.java @@ -442,7 +442,7 @@ public class SeriesEditDialog extends DataEntryDialog { } @Override - public void onRowRemoved() { + public void onRowRemoved(int rowIndex) { updateFromToListboxesSelection(); updateHintLabel(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java index f1540cf0061..31460a3e146 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoCreateDialog.java @@ -5,14 +5,15 @@ import java.util.Date; import java.util.List; import com.google.gwt.user.client.ui.Label; +import com.sap.sailing.gwt.ui.adminconsole.EventDialog.FileStorageServiceConnectionTestObservable; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.common.media.MimeType; import com.sap.sse.gwt.client.media.VideoDTO; public class VideoCreateDialog extends VideoDialog { - public VideoCreateDialog(String initialTag, StringMessages stringMessages, DialogCallback callback) { - super(new Date(), new VideoParameterValidator(stringMessages), stringMessages, callback); + public VideoCreateDialog(String initialTag, StringMessages stringMessages, FileStorageServiceConnectionTestObservable storageServiceAvailable, DialogCallback callback) { + super(new Date(), new VideoParameterValidator(stringMessages), stringMessages, storageServiceAvailable, callback); createdAtLabel = new Label(creationDate.toString()); titleTextBox = createTextBox(null); titleTextBox.setVisibleLength(50); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java index c2d138576c5..63a1c4f5968 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -14,9 +14,11 @@ import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.ui.adminconsole.EventDialog.FileStorageServiceConnectionTestObservable; +import com.sap.sailing.gwt.ui.adminconsole.EventDialog.FileStorageServiceConnectionTestObserver; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sse.common.Util; +import com.sap.sse.common.media.MediaTagConstants; import com.sap.sse.common.media.MimeType; import com.sap.sse.gwt.adminconsole.URLFieldWithFileUpload; import com.sap.sse.gwt.client.GWTLocaleUtil; @@ -27,7 +29,7 @@ import com.sap.sse.gwt.client.controls.listedit.StringListInlineEditorComposite; import com.sap.sse.gwt.client.dialog.DataEntryDialog; import com.sap.sse.gwt.client.media.VideoDTO; -public abstract class VideoDialog extends DataEntryDialog { +public abstract class VideoDialog extends DataEntryDialog implements FileStorageServiceConnectionTestObserver { protected final StringMessages stringMessages; protected final URLFieldWithFileUpload videoURLAndUploadComposite; protected final Date creationDate; @@ -61,7 +63,7 @@ public abstract class VideoDialog extends DataEntryDialog { } } - public VideoDialog(Date createdAtDate, VideoParameterValidator validator, StringMessages stringMessages, DialogCallback callback) { + public VideoDialog(Date createdAtDate, VideoParameterValidator validator, StringMessages stringMessages, FileStorageServiceConnectionTestObservable storageServiceAvailable, DialogCallback callback) { super(stringMessages.video(), null, stringMessages.ok(), stringMessages.cancel(), validator, callback); this.stringMessages = stringMessages; @@ -83,17 +85,19 @@ public abstract class VideoDialog extends DataEntryDialog { for (String locale : GWTLocaleUtil.getAvailableLocalesAndDefault()) { localeListBox.addItem(GWTLocaleUtil.getDecoratedLanguageDisplayNameWithDefaultLocaleSupport(locale), locale == null ? "" : locale); } - videoURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); + videoURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages, false); videoURLAndUploadComposite.addValueChangeHandler(new ValueChangeHandler() { @Override public void onValueChange(ValueChangeEvent event) { validateAndUpdate(); } }); - thumbnailURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages); + thumbnailURLAndUploadComposite = new URLFieldWithFileUpload(stringMessages, false); tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), new GenericStringListInlineEditorComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ - MediaConstants.videoTagSuggestions, stringMessages.enterTagsForTheVideo(), 50)); + MediaTagConstants.videoTagSuggestions, stringMessages.enterTagsForTheVideo(), 50)); + //the observer has to be registered after creating the URLFieldWithFileUpload + storageServiceAvailable.registerObserver(this); } @Override @@ -187,4 +191,10 @@ public abstract class VideoDialog extends DataEntryDialog { protected FocusWidget getInitialFocusWidget() { return videoURLAndUploadComposite.getInitialFocusWidget(); } + + @Override + public void onFileStorageServiceTestPassed() { + videoURLAndUploadComposite.setUploadEnabled(true); + thumbnailURLAndUploadComposite.setUploadEnabled(true); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java index 29d8811bd7e..db485d9d563 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoEditDialog.java @@ -4,12 +4,13 @@ import java.util.ArrayList; import java.util.List; import com.google.gwt.user.client.ui.Label; +import com.sap.sailing.gwt.ui.adminconsole.EventDialog.FileStorageServiceConnectionTestObservable; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.gwt.client.media.VideoDTO; public class VideoEditDialog extends VideoDialog { - public VideoEditDialog(VideoDTO video, StringMessages stringMessages, DialogCallback callback) { - super(video.getCreatedAtDate(), new VideoParameterValidator(stringMessages), stringMessages, callback); + public VideoEditDialog(VideoDTO video, StringMessages stringMessages, FileStorageServiceConnectionTestObservable storageServiceAvailable, DialogCallback callback) { + super(video.getCreatedAtDate(), new VideoParameterValidator(stringMessages), stringMessages, storageServiceAvailable, callback); createdAtLabel = new Label(video.getCreatedAtDate().toString()); videoURLAndUploadComposite.setURL(video.getSourceRef()); titleTextBox = createTextBox(video.getTitle()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java index 66288239a0a..97fe3e3e238 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideosListComposite.java @@ -27,6 +27,7 @@ import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.view.client.ListDataProvider; import com.google.gwt.view.client.SelectionChangeEvent; import com.google.gwt.view.client.SingleSelectionModel; +import com.sap.sailing.gwt.ui.adminconsole.EventDialog.FileStorageServiceConnectionTestObservable; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil; import com.sap.sse.common.media.MediaTagConstants; @@ -49,6 +50,7 @@ public class VideosListComposite extends Composite { private SingleSelectionModel videoSelectionModel; private ListDataProvider videoListDataProvider; private final Label noVideosLabel; + private final FileStorageServiceConnectionTestObservable storageServiceAvailable; private final SimplePanel mainPanel; private final VerticalPanel panel; @@ -69,9 +71,9 @@ public class VideosListComposite extends Composite { private final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class); - public VideosListComposite(final StringMessages stringMessages) { + public VideosListComposite(final StringMessages stringMessages, FileStorageServiceConnectionTestObservable storageServiceAvailable) { this.stringMessages = stringMessages; - + this.storageServiceAvailable = storageServiceAvailable; mainPanel = new SimplePanel(); panel = new VerticalPanel(); mainPanel.setWidget(panel); @@ -84,7 +86,7 @@ public class VideosListComposite extends Composite { createVideoBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openCreateVideoDialog(MediaTagConstants.GALLERY); + openCreateVideoDialog(MediaTagConstants.GALLERY.getName()); } }); videosControlsPanel.add(createVideoBtn); @@ -93,7 +95,7 @@ public class VideosListComposite extends Composite { addLiveStreamBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openCreateVideoDialog(MediaTagConstants.LIVESTREAM); + openCreateVideoDialog(MediaTagConstants.LIVESTREAM.getName()); } }); videosControlsPanel.add(addLiveStreamBtn); @@ -102,7 +104,7 @@ public class VideosListComposite extends Composite { addHighlightBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - openCreateVideoDialog(MediaTagConstants.HIGHLIGHT); + openCreateVideoDialog(MediaTagConstants.HIGHLIGHT.getName()); } }); videosControlsPanel.add(addHighlightBtn); @@ -247,33 +249,35 @@ public class VideosListComposite extends Composite { } private void openCreateVideoDialog(String initialTag) { - VideoCreateDialog dialog = new VideoCreateDialog(initialTag, stringMessages, new DialogCallback() { - @Override - public void cancel() { - } + VideoCreateDialog dialog = new VideoCreateDialog(initialTag, stringMessages, storageServiceAvailable, + new DialogCallback() { + @Override + public void cancel() { + } - @Override - public void ok(VideoDTO newVideo) { - videoListDataProvider.getList().add(newVideo); - updateTableVisisbilty(); - } - }); + @Override + public void ok(VideoDTO newVideo) { + videoListDataProvider.getList().add(newVideo); + updateTableVisisbilty(); + } + }); dialog.show(); } private void openEditVideoDialog(final VideoDTO selectedVideo) { - VideoEditDialog dialog = new VideoEditDialog(selectedVideo, stringMessages, new DialogCallback() { - @Override - public void cancel() { - } + VideoEditDialog dialog = new VideoEditDialog(selectedVideo, stringMessages, storageServiceAvailable, + new DialogCallback() { + @Override + public void cancel() { + } - @Override - public void ok(VideoDTO updatedVideo) { - videoListDataProvider.getList().remove(selectedVideo); - videoListDataProvider.getList().add(updatedVideo); - updateTableVisisbilty(); - } - }); + @Override + public void ok(VideoDTO updatedVideo) { + videoListDataProvider.getList().remove(selectedVideo); + videoListDataProvider.getList().add(updatedVideo); + updateTableVisisbilty(); + } + }); dialog.show(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 4c14d8ef957..f8186705af1 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -121,6 +121,7 @@ import com.sap.sse.common.mail.MailException; import com.sap.sse.gwt.client.ServerInfoDTO; import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtService; import com.sap.sse.gwt.client.media.ImageDTO; +import com.sap.sse.gwt.client.media.ImageResizingTaskDTO; import com.sap.sse.gwt.client.media.VideoDTO; import com.sap.sse.gwt.client.replication.RemoteReplicationService; @@ -784,4 +785,18 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS * Checks if the given race is currently in state tracking or loading. */ Boolean checkIfRaceIsTracking(RegattaAndRaceIdentifier race); + + /** + * Resizes an {@Link ImageDTO} that is part of an {@link ImageResizingTaskDTO} into a set of resized versions. This set only contains one image in most cases, because most {@Link ImageDTO} only hold one predefined {@link MediaTagConstants}. + * All {@link MediaTagConstants} stored in the resizingTask of the {@link ImageResizingTaskDTO} create a resize. Since no {@link MediaTagConstants} have the same defined bounds, there will be no merge of these {@Link ImageDTO}. + * Uses the {@link FileStorageService} to store the resized images. + * If an error occurs during resize or storing process, it will be tried to restore the previous state. + * + * @author Robin Fleige (D067799) + * + * @param imageResizingTask is an {@link ImageResizingTaskDTO} with the information on how the image saved in the {@Link ImageDTO} should be resized. The resizingTask attribute should not be null or empty at this point + * @return returns a set of {@Link ImageDTO}, that contain the resized variants of the {@Link ImageDTO} in toResizeImage + * @throws Exception can throw different type of exceptions + */ + Set resizeImage(ImageResizingTaskDTO imageResizingTask) throws Exception; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 2c15a4c405e..4badb850574 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -108,6 +108,7 @@ import com.sap.sse.common.Util.Triple; import com.sap.sse.gwt.client.ServerInfoRetriever; import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtServiceAsync; import com.sap.sse.gwt.client.media.ImageDTO; +import com.sap.sse.gwt.client.media.ImageResizingTaskDTO; import com.sap.sse.gwt.client.media.VideoDTO; import com.sap.sse.gwt.client.replication.RemoteReplicationServiceAsync; import com.sap.sse.pairinglist.PairingList; @@ -990,4 +991,11 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan * @see SailingService#checkIfRaceIsTracking(RegattaAndRaceIdentifier) */ void checkIfRaceIsTracking(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback asyncCallback); + + /** + * @see SailingService#resizeImage(ImageResizingTaskDTO) + * @param imageResizingTask the information on how the contained ImageDTO should be resized + * @param asyncCallback The callback called after finishing resizing, storing the returned ImageDTOs somewhere is proposed + */ + void resizeImage(ImageResizingTaskDTO imageResizingTask, AsyncCallback> asyncCallback); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 4b81c3a8504..59f1951b697 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -411,6 +411,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String successfullyUpdatedResultImportUrls(); String errorRemovingResultImportUrls(String message); String pleaseEnterNonEmptyUrl(); + String pleaseEnterNonEmptyUrlOrUploadImage(); String addResultImportUrl(); String errorAddingResultImportUrl(String message); String remoteServerInstances(); @@ -1480,6 +1481,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String addEventLogo(); String noImagesDefinedYet(); String imageSizeError(String imageType, int minWidth, int maxWidth, int minHeight, int maxHeight); + String imageToSmallError(String imageType, int minWidth, int minHeight); + String imageResizeError(String imageType, double minRatio, double maxRatio, double ratio); String couldNotRetrieveImageSizeYet(); @Override String pleaseOnlyUploadContentYouHaveAllUsageRightsFor(); @@ -2099,4 +2102,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String swissTimingUpdateURL(); String swissTimingUpdateUsername(); String swissTimingUpdatePassword(); + String allowResizing(); + String resizeSuccessfull(); + String resizeUnsuccessfull(); + String automaticResizeNeedsStorageService(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index cc6cc82adcc..9503b648a84 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -433,6 +433,7 @@ errorRefreshingResultImportUrlList=Error refreshing result import URL list: {0} successfullyUpdatedResultImportUrls=Successfully updated result import URL list errorRemovingResultImportUrls=Error removing result import URLs: {0} pleaseEnterNonEmptyUrl=Please enter a URL. +pleaseEnterNonEmptyUrlOrUploadImage=Please enter a URL or upload an image. addResultImportUrl=Add result import URL errorAddingResultImportUrl=Error adding result import URL: {0} remoteServerInstances=Remote Server Instances @@ -1470,7 +1471,9 @@ addStageImage=Add stage image addTeaserImage=Add teaser image addEventLogo=Add event logo noImagesDefinedYet=No images defined yet -imageSizeError=The size of the {0} image does not fit. The width should be between {1} and {2} px and the height between {3} and {4} px. +imageSizeError=The size of the {0} image does not fit. The width should be between {1} and {2} px and the height between {3} and {4} px. Try turning on resizing. +imageToSmallError=The size of the {0} image does not fit. The width should be at least {1} px and the height at least {2} px. +imageResizeError=Resizing of the {0} image does not work. The width/height ratio should be between {1} and {2}, but actually is {3}. couldNotRetrieveImageSizeYet=The width and height of the image could not be retrieved yet. pleaseOnlyUploadContentYouHaveAllUsageRightsFor=Please only upload content you have all usage rights for. Remember that content may be cropped. registerCompetitorsOnRace=Register Competitors on Race (e.g. for split-fleet racing) @@ -2094,4 +2097,9 @@ audioFiles=Audio tracks selectMedia=Select Media swissTimingUpdateURL=Update URL (e.g., for start time and course change feedback) swissTimingUpdateUsername=Username for sending updates -swissTimingUpdatePassword=Password for sending updates \ No newline at end of file +swissTimingUpdatePassword=Password for sending updates +allowResizing=Allow resizing +resizeSuccessfull=Resizing successfully finished +resizeUnsuccessfull=Resizing not possible +setUpStorageService=Please set up a file storage service first +automaticResizeNeedsStorageService=Automatic Resizing needs a working FileStorageService. \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 76efc51b1e0..61ce79a6a65 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -434,6 +434,7 @@ errorRefreshingResultImportUrlList=Fehler beim Aktualisieren der Ergebnisimport successfullyUpdatedResultImportUrls=Ergebnisimport URL-Liste erfolgreich aktualisiert errorRemovingResultImportUrls=Fehler beim Löschen von Ergebnisimport URLs: {0} pleaseEnterNonEmptyUrl=Bitte gebe eine URL ein. +pleaseEnterNonEmptyUrlOrUploadImage=Bitte gebe eine URL an oder lade ein Bild hoch. addResultImportUrl=Ergebnisimport-URL hinzufügen errorAddingResultImportUrl=Fehler beim Hinzufügen einer Ergebnisimport URL: {0} remoteServerInstances=Remote-Server Instanzen @@ -1453,7 +1454,9 @@ addStageImage=Startseiten-Bild hinzufügen addTeaserImage=Lock-Bild hinzufügen addEventLogo=Veranstaltungs-Logo hinzufügen noImagesDefinedYet=Noch keine Bilder vorhanden -imageSizeError=Die Größe des {0}-Bildes ist unpassend. Die Breite sollte zwischen {1} und {2} px und die Höhe zwischen {3} und {4} px sein. +imageSizeError=Die Größe des {0}-Bildes ist unpassend. Die Breite sollte zwischen {1} und {2} px und die Höhe zwischen {3} und {4} px sein. Versuche die Skalierung einzuschalten. +imageToSmallError=Die Größe des {0}-Bildes ist unpassend. Die Breite sollte mindestens {1} px und die Höhe mindestens {2} px sein. +imageResizeError=Die Skalierung des {0}-Bildes hat nicht funktionoiert. Das Breite/Höhe Verhältnis sollte zwischen {1} und {2} sein, ist aber {3}. couldNotRetrieveImageSizeYet=Bildgröße konnte noch nicht ermittelt werden. pleaseOnlyUploadContentYouHaveAllUsageRightsFor=Bitte nur Inhalte hochladen, für die alle Verwendungsrechte vorliegen. Bitte beachten: Bilder können verändert wiedergegeben werden. registerCompetitorsOnRace=Teilnehmer auf dem Rennen registrieren (z.B. für Split-Fleets) @@ -2089,4 +2092,9 @@ audioFiles=Tonspuren selectMedia=Medium auswählen swissTimingUpdateURL=Update URL (z.B. für Startzeit-Übertragung) swissTimingUpdateUsername=Benutzername zum Versenden der Updates -swissTimingUpdatePassword=Passwort zum Versenden der Updates \ No newline at end of file +swissTimingUpdatePassword=Passwort zum Versenden der Updates +allowResizing=Skalierung erlauben +resizeSuccessfull=Skalierung erfolgreich abgeschlossen +resizeUnsuccessfull=Skalierung nicht möglich +setUpStorageService=Bitte setze zuerst einen Datei Speicher auf +automaticResizeNeedsStorageService=Die automatische Skalierung benötigt einen funktionierenden FileStorageService. \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index e0a2a9d32b3..2c29298449f 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -1,5 +1,6 @@ package com.sap.sailing.gwt.ui.server; +import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.FilterInputStream; @@ -52,6 +53,8 @@ import java.util.regex.Pattern; import java.util.stream.StreamSupport; import java.util.zip.GZIPInputStream; +import javax.imageio.metadata.IIOMetadata; +import javax.management.InvalidAttributeValueException; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -544,12 +547,15 @@ import com.sap.sse.common.impl.DegreeBearingImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.TimeRangeImpl; import com.sap.sse.common.mail.MailException; +import com.sap.sse.common.media.MediaTagConstants; import com.sap.sse.common.media.MimeType; import com.sap.sse.filestorage.FileStorageManagementService; import com.sap.sse.filestorage.FileStorageService; import com.sap.sse.filestorage.InvalidPropertiesException; +import com.sap.sse.filestorage.OperationFailedException; import com.sap.sse.gwt.client.ServerInfoDTO; import com.sap.sse.gwt.client.media.ImageDTO; +import com.sap.sse.gwt.client.media.ImageResizingTaskDTO; import com.sap.sse.gwt.client.media.VideoDTO; import com.sap.sse.gwt.dispatch.servlets.ProxiedRemoteServiceServlet; import com.sap.sse.gwt.server.filestorage.FileStorageServiceDTOUtils; @@ -585,6 +591,8 @@ import com.sap.sse.shared.media.VideoDescriptor; import com.sap.sse.shared.media.impl.ImageDescriptorImpl; import com.sap.sse.shared.media.impl.VideoDescriptorImpl; import com.sap.sse.util.HttpUrlConnectionHelper; +import com.sap.sse.util.ImageConverter; +import com.sap.sse.util.ImageConverter.ImageWithMetadata; import com.sap.sse.util.ServiceTrackerFactory; import com.sap.sse.util.ThreadPoolUtil; import com.sapsailing.xrr.structureimport.eventimport.RegattaJSON; @@ -6720,6 +6728,9 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public FileStorageServicePropertyErrorsDTO testFileStorageServiceProperties(String serviceName, String localeInfoName) throws IOException { try { + if (serviceName == null) { + serviceName = getActiveFileStorageServiceName(); + } FileStorageService service = getFileStorageService(serviceName); if (service != null) { service.testProperties(); @@ -7937,4 +7948,109 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } } } + + @Override + public Set resizeImage(final ImageResizingTaskDTO resizingTask) throws Exception { + if (resizingTask.getResizingTask() == null || resizingTask.getResizingTask().size() == 0) { + throw new InvalidAttributeValueException("Resizing Task can not be null or empty"); + } + final ImageConverter converter = new ImageConverter(); + // calculating the fileType of the image by its uri + final String sourceRef = resizingTask.getImage().getSourceRef(); + final String fileType = sourceRef.substring(sourceRef.lastIndexOf(".") + 1); + final ImageWithMetadata imageAndMetadata = converter + .loadImage(HttpUrlConnectionHelper.redirectConnection(new URL(sourceRef)).getInputStream(), fileType); + final List resizedImages = converter.convertImage(imageAndMetadata.getImage(), + resizingTask.getResizingTask()); + final List sourceRefs = storeImages(resizedImages, fileType, imageAndMetadata.getMetadata()); + // if an error occures while storing the files, all already stored files are removed before throwing an + // exception + if (sourceRefs == null || sourceRefs.size() < resizingTask.getResizingTask().size()) { + for (String alreadyStoredFileRef : sourceRefs) { + try { + getService().getFileStorageManagementService().getActiveFileStorageService() + .removeFile(new URI(alreadyStoredFileRef)); + } catch (Exception e) { + } + // Exception occured while trying to revert changes after exception + // This only keeps some trash on the FileStorage + } + throw new Exception("Error occured while storing images on the FileStorage"); + } + final Set resizedImagesAsDTOs = createImageDTOsFromURLsAndResizingTask(sourceRefs, resizingTask, + resizedImages); + for (String tag : resizingTask.getImage().getTags()) { + final MediaTagConstants predefinedTag = MediaTagConstants.fromName(tag); + if (predefinedTag != null && !resizingTask.getResizingTask().contains(predefinedTag)) { + final ImageDTO image = resizingTask.getImage(); + for (MediaTagConstants tagConstant : resizingTask.getResizingTask()) { + image.getTags().remove(tagConstant.getName()); + } + resizedImagesAsDTOs.add(image); + } + } + return resizedImagesAsDTOs; + } + + /** + * Takes a list of source URLs, the resizing task and the sizes of the resized images to create a ImageDTO for every + * resized image + * + * @author Robin Fleige (D067799) + * + * @param sourceRefs + * list of source URLs + * @param resizingTask + * the resizing task, with information about resizes and the original ImageDTO + * @param images + * the BufferedImages, used to get their width and height + * @returns a List of ImageDTOs that contains an ImageDTO per resized image + */ + private Set createImageDTOsFromURLsAndResizingTask(final List sourceRefs, + final ImageResizingTaskDTO resizingTask, final List images) { + final Set imageDTOs = new HashSet(); + for (int i = 0; i < sourceRefs.size(); i++) { + final ImageDTO imageDTO = resizingTask.cloneImageDTO(); + for (MediaTagConstants tag : MediaTagConstants.values()) { + imageDTO.getTags().remove(tag.getName()); + } + imageDTO.getTags().add(resizingTask.getResizingTask().get(i).getName()); + imageDTO.setSourceRef(sourceRefs.get(i)); + imageDTO.setSizeInPx(images.get(i).getWidth(), images.get(i).getHeight()); + imageDTOs.add(imageDTO); + } + return imageDTOs; + } + + /** + * Stores a list of BufferedImages and returns a list of URLs as Strings under which the BufferedImages are stored + * + * @author Robin Fleige (D067799) + * + * @param resizedImages + * the BufferedImages that will be stored + * @param fileType + * the format of the image, for example "png", "jpeg" or "jpg" + * @param metadata + * the metadata of the original image + * @returns a list of URLs as Strings under which the BufferedImages are stored + */ + private List storeImages(final List resizedImages, final String fileType, + final IIOMetadata metadata) { + final List sourceRefs = new ArrayList<>(); + + try { + for (final BufferedImage resizedImage : resizedImages) { + final InputStream fileStorageStream = new ImageConverter().imageWithMetadataToInputStream(resizedImage, + metadata, fileType); + sourceRefs.add(getService().getFileStorageManagementService().getActiveFileStorageService() + .storeFile(fileStorageStream, "." + fileType, new Long(fileStorageStream.available())) + .toString()); + } + } catch (NoCorrespondingServiceRegisteredException | IOException | OperationFailedException + | InvalidPropertiesException e) { + logger.log(Level.SEVERE, "Could not store file. Cause: " + e.getMessage()); + } + return sourceRefs; + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java index 20a77b0b9de..195233e69a5 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java @@ -75,7 +75,7 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable, SecuredObj public ImageDTO getLogoImage() { ImageDTO result = null; for (ImageDTO image : images) { - if (image.hasTag(MediaTagConstants.LOGO)) { + if (image.hasTag(MediaTagConstants.LOGO.getName())) { result = image; break; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java deleted file mode 100755 index f554ce28962..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/media/MediaConstants.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.sap.sailing.gwt.ui.shared.media; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import com.sap.sse.common.media.MediaTagConstants; -import com.sap.sse.common.media.MimeType; - -public final class MediaConstants { - - // perfect fit would be 1440 x 580 - public static final int MIN_STAGE_IMAGE_WIDTH = 1440 / 2; - public static final int MAX_STAGE_IMAGE_WIDTH = 1440 * 2; - public static final int MIN_STAGE_IMAGE_HEIGHT = 580 / 2; - public static final int MAX_STAGE_IMAGE_HEIGHT = 580 * 2; - - // perfect fit would be 370 x 240 - public static final int MIN_EVENTTEASER_IMAGE_WIDTH = 370 / 2; - public static final int MAX_EVENTTEASER_IMAGE_WIDTH = 370 * 3; - public static final int MIN_EVENTTEASER_IMAGE_HEIGHT = 240 / 2; - public static final int MAX_EVENTTEASER_IMAGE_HEIGHT = 240 * 3; - - // perfect fit would be 140 x 140 - public static final int MIN_LOGO_IMAGE_WIDTH = 140 / 2; - public static final int MAX_LOGO_IMAGE_WIDTH = 140 * 4; - public static final int MIN_LOGO_IMAGE_HEIGHT = 140 / 2; - public static final int MAX_LOGO_IMAGE_HEIGHT = 140 * 4; - - public static final List imageTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.BIGSCREEN,MediaTagConstants.STAGE, MediaTagConstants.TEASER, - MediaTagConstants.SPONSOR, MediaTagConstants.LOGO, MediaTagConstants.GALLERY }); - public static final Iterable videoTagSuggestions = Arrays.asList(new String[] { MediaTagConstants.BIGSCREEN,MediaTagConstants.LIVESTREAM, MediaTagConstants.HIGHLIGHT, MediaTagConstants.FEATURED, MediaTagConstants.STAGE }); - public static final Set SUPPORTED_VIDEO_TYPES = new HashSet<>(Arrays.asList(MimeType.youtube, MimeType.vimeo, MimeType.mp4, MimeType.mp4panorama, MimeType.mp4panoramaflip)); - - private MediaConstants() { - } - -} diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java index 601038e8f9b..23d486d1898 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java @@ -367,12 +367,12 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest Event event = new EventImpl(eventName, eventStartDate, eventEndDate, venue, /*isPublic*/ true, UUID.randomUUID()); ImageDescriptor image1 = new ImageDescriptorImpl(imageURL, createdAt); - image1.addTag(MediaTagConstants.GALLERY); + image1.addTag(MediaTagConstants.GALLERY.getName()); event.addImage(image1); ImageDescriptor image2 = new ImageDescriptorImpl(sponsorImageURL, createdAt); event.addImage(image2); - image2.addTag(MediaTagConstants.SPONSOR); + image2.addTag(MediaTagConstants.SPONSOR.getName()); VideoDescriptor video1 = new VideoDescriptorImpl(videoURL, MimeType.mp4, createdAt); event.addVideo(video1); @@ -383,8 +383,8 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest final Event loadedEvent = dof.loadEvent(eventName); assertEquals(2, Util.size(loadedEvent.getImages())); assertEquals(1, Util.size(loadedEvent.getVideos())); - assertEquals(1, Util.size(loadedEvent.findImagesWithTag(MediaTagConstants.GALLERY))); - assertEquals(1, Util.size(loadedEvent.findImagesWithTag(MediaTagConstants.SPONSOR))); + assertEquals(1, Util.size(loadedEvent.findImagesWithTag(MediaTagConstants.GALLERY.getName()))); + assertEquals(1, Util.size(loadedEvent.findImagesWithTag(MediaTagConstants.SPONSOR.getName()))); assertEquals(1, Util.size(loadedEvent.getVideos())); } diff --git a/java/com.sap.sailing.targetplatform.base/plugins/target-base/org.apache.servicemix.bundles.aws-java-sdk-1.10.73_1.jar b/java/com.sap.sailing.targetplatform.base/plugins/target-base/org.apache.servicemix.bundles.aws-java-sdk-1.10.73_1.jar old mode 100755 new mode 100644 diff --git a/java/com.sap.sailing.targetplatform.base/pom.xml b/java/com.sap.sailing.targetplatform.base/pom.xml index 663611aa4dd..9089a4b2781 100644 --- a/java/com.sap.sailing.targetplatform.base/pom.xml +++ b/java/com.sap.sailing.targetplatform.base/pom.xml @@ -20,7 +20,7 @@ org.eclipse.tycho.extras tycho-p2-extras-plugin - ${tycho-version} + 1.0.0 ${basedir} diff --git a/java/com.sap.sailing.targetplatform/definitions/README_P2ADMIN b/java/com.sap.sailing.targetplatform/definitions/README_P2ADMIN index a12204b1ff9..360ed478ef7 100644 --- a/java/com.sap.sailing.targetplatform/definitions/README_P2ADMIN +++ b/java/com.sap.sailing.targetplatform/definitions/README_P2ADMIN @@ -1,3 +1,3 @@ The former "p2admin" target definition is not tracked in the repository anymore. Instead, it can be generated from the existing target definition via ``../scripts/createLocalTargetDef.sh``. -This script copies the existing target definition and replaces the remote URL ``http://p2.sapsailing.com/p2/sailing/`` with a local ``file://`` URL. +This script copies the existing target definition and replaces the remote URL ``https://p2.sapsailing.com/p2/sailing/`` with a local ``file://`` URL. diff --git a/java/com.sap.sailing.targetplatform/scripts/createLocalTargetDef.sh b/java/com.sap.sailing.targetplatform/scripts/createLocalTargetDef.sh index e38201b5bc3..aa90859d039 100755 --- a/java/com.sap.sailing.targetplatform/scripts/createLocalTargetDef.sh +++ b/java/com.sap.sailing.targetplatform/scripts/createLocalTargetDef.sh @@ -1,9 +1,10 @@ #!/bin/bash +source ./../../../configuration/correctFilePathInRelationToCurrentOs.sh # generate a target definition pointing to the locally built p2 repo from the race-analysis-p2-remote target defintion - base="../definitions/race-analysis-p2" -remote_repo="http://p2.sapsailing.com/p2/sailing/" -local_repo="file://`readlink -f ../../com.sap.sailing.targetplatform.base/target/repository/ | sed -e 's/\/cygdrive\/\(.\)/\/\1:/'`" - +remote_repo="https://p2.sapsailing.com/p2/sailing/" +#reading the filepath and editing it, so it fits for eclipse #currently save works for cygwin, gitbash and linux +local_repo=$(correct_file_path "`readlink -f ../../com.sap.sailing.targetplatform.base/target/repository/`") +local_repo="file:/$local_repo" # replace remote p2-repo URL with local repo URL sed -e "/^ $base-local.target diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index bb2da27da23..026756816b6 100755 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -21,8 +21,14 @@

Release Notes - Administration Console

- -

July 2018

+

September 2018

+
    +
  • Added automatic resizing when adding images to an event using the ImageDialog. + It shows a check box if resizing is necessary, if you check it, the service will resize the image for you.
  • +
  • Now showing an error when trying to upload an image or video to an event and no working FileStorageService is registered.
  • +
+ +

August 2018

  • The mark passing editor now uses a full date/time format for the mark passing time points.
  • The TracTrac connector panel no longer shows a password visibly but uses a password text field.
  • diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java index e0f21ff54c8..cd353af4537 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/MediaTagConstants.java @@ -1,13 +1,70 @@ package com.sap.sse.common.media; -public interface MediaTagConstants { - static final String GALLERY = "Gallery"; - static final String STAGE = "Stage"; - static final String LOGO = "Logo"; - static final String TEASER = "Teaser"; - static final String SPONSOR = "Sponsor"; - static final String HIGHLIGHT = "Highlight"; - static final String LIVESTREAM = "Livestream"; - static final String FEATURED = "Featured"; - static final String BIGSCREEN = "BigScreen"; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public enum MediaTagConstants { + GALLERY("Gallery", 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE), + STAGE("Stage", 1440 / 2, 1440 * 2, 580 / 2, 580 * 2), // perfect fit would be 1440 x 580 + LOGO("Logo", 140 / 2, 140 * 4, 140 / 2, 140 * 4), // perfect fit would be 140 x 140 + TEASER("Teaser", 370 / 2, 370 * 3, 240 / 2, 240 * 3), // perfect fit would be 370 x 240 + SPONSOR("Sponsor", 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE), + HIGHLIGHT("Highlight", 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE), + LIVESTREAM("Livestream", 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE), + FEATURED("Featured", 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE), + BIGSCREEN("BigScreen", 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE); + + private final String name; + private final int minWidth; + private final int maxWidth; + private final int minHeight; + private final int maxHeight; + + public static final List imageTagSuggestions = Arrays.asList(new String[] { BIGSCREEN.getName(), + STAGE.getName(), TEASER.getName(), SPONSOR.getName(), LOGO.getName(), GALLERY.getName() }); + public static final List videoTagSuggestions = Arrays.asList(new String[] { BIGSCREEN.getName(), + LIVESTREAM.getName(), HIGHLIGHT.getName(), FEATURED.getName(), STAGE.getName() }); + public static final Set SUPPORTED_VIDEO_TYPES = new HashSet<>(Arrays.asList(MimeType.youtube, + MimeType.vimeo, MimeType.mp4, MimeType.mp4panorama, MimeType.mp4panoramaflip)); + + private MediaTagConstants(String name, int minWidth, int maxWidth, int minHeight, int maxHeight) { + this.name = name; + this.minWidth = minWidth; + this.maxWidth = maxWidth; + this.minHeight = minHeight; + this.maxHeight = maxHeight; + } + + public String getName() { + return name; + } + + public int getMinWidth() { + return minWidth; + } + + public int getMaxWidth() { + return maxWidth; + } + + public int getMinHeight() { + return minHeight; + } + + public int getMaxHeight() { + return maxHeight; + } + + public static MediaTagConstants fromName(String name) { + MediaTagConstants toReturn = null; + for (MediaTagConstants mediaTagConstant : MediaTagConstants.values()) { + if (mediaTagConstant.getName().equals(name)) { + toReturn = mediaTagConstant; + } + } + return toReturn; + } + } diff --git a/java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/impl/AmazonS3FileStorageServiceImpl.java b/java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/impl/AmazonS3FileStorageServiceImpl.java index 579370d34ef..e83dfd7df09 100644 --- a/java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/impl/AmazonS3FileStorageServiceImpl.java +++ b/java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/impl/AmazonS3FileStorageServiceImpl.java @@ -109,7 +109,7 @@ public class AmazonS3FileStorageServiceImpl extends BaseFileStorageServiceImpl i @Override public void removeFile(URI uri) throws InvalidPropertiesException, OperationFailedException { - String key = uri.getPath().substring(1); // remove initial slash + String key = uri.getPath().substring(uri.getPath().lastIndexOf("/")+1); AmazonS3Client s3Client = createS3Client(); try { s3Client.deleteObject(new DeleteObjectRequest(bucketName.getValue(), key)); @@ -123,12 +123,16 @@ public class AmazonS3FileStorageServiceImpl extends BaseFileStorageServiceImpl i public void testProperties() throws InvalidPropertiesException { AmazonS3Client s3 = createS3Client(); + + if (bucketName.getValue().equals("")) { + throw new InvalidPropertiesException("empty bucketname is not allowed"); + } // test if credentials are valid // TODO seems to even work if credentials are not valid if bucket is publicly visible try { s3.doesBucketExist(bucketName.getValue()); } catch (Exception e) { - throw new InvalidPropertiesException("invalid credentials or not enough access rights for the bucket", e, + throw new InvalidPropertiesException("invalid credentials or not enough access rights for the bucket" + e.getCause(), e, new Pair(accessId, "seems to be invalid"), new Pair(accessKey, "seems to be invalid")); } diff --git a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/StringMessages.java b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/StringMessages.java index 2ba8ea6bec7..aa9457f3c25 100755 --- a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/StringMessages.java +++ b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/StringMessages.java @@ -93,4 +93,6 @@ public interface StringMessages extends Messages { String explainReplicationServletPort(); String ok(); + + String setUpStorageService(); } diff --git a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java index ae7f57a6396..b63c0873494 100755 --- a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java +++ b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java @@ -47,7 +47,15 @@ public class URLFieldWithFileUpload extends Composite implements HasValue]*>(.*)", "$1")); } + + public void setUploadEnabled(boolean uploadEnabled) { + if (uploadEnabled) { + uploadFormPanel.add(uploadPanel); + } else { + uploadFormPanel.remove(uploadPanel); + } + } } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/CollapsedListEditorUi.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/CollapsedListEditorUi.java index 97bee0018e1..2e24402c20b 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/CollapsedListEditorUi.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/CollapsedListEditorUi.java @@ -24,7 +24,7 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; * {@link ListEditorComposite} with the respective {@link ExpandedListEditorUi} strategy that will be passed through * from this class's constructor to the {@link #createExpandedUi(List, ExpandedListEditorUi)} method.

    * - * Implementing subclasses may choose to override the {@link #onRowAdded()} and/or the {@link #onRowRemoved()} method(s) + * Implementing subclasses may choose to override the {@link #onRowAdded()} and/or the {@link #onRowRemoved(int)} method(s) * to be notified of changes to the list. * * @author Lukas Niemeier @@ -123,7 +123,7 @@ public abstract class CollapsedListEditorUi extends ListEditorUi * - * Implementing subclasses may choose to override the {@link #onRowAdded()} and/or the {@link #onRowRemoved()} method(s) + * Implementing subclasses may choose to override the {@link #onRowAdded()} and/or the {@link #onRowRemoved(int)} method(s) * to be notified of changes to the list. Alternatively or in addition, clients can * {@link ListEditorComposite#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) add a value * change handler} to the enclosing {@link ListEditorComposite}. @@ -37,7 +37,7 @@ import com.sap.sse.gwt.client.StringMessages; public abstract class ExpandedListEditorUi extends ListEditorUi { private final ImageResource removeImage; - private Grid expandedValuesGrid; + protected Grid expandedValuesGrid; private final boolean canRemoveItems; /** @@ -80,7 +80,7 @@ public abstract class ExpandedListEditorUi extends ListEditorUi extends ListEditorUi extends ListEditorUi + * The type of the items in the list + */ +public class ExpandedUiWithCheckboxes extends GenericStringListInlineEditorComposite.ExpandedUi { + + private final List checkBoxes; + private final String checkBoxText; + private final List changeHandler = new ArrayList<>(); + static final ListEditorResources ress = GWT.create(ListEditorResources.class); + + /** + * Creates an editable list with checkboxes for every entry + * + * @param stringMessages + * the holder of the used strings + * @param removeImage + * the icon for removing an entry from the editor + * @param suggestValues + * values that will be suggested when entering something into the editor + * @param placeholderTextForAddTextbox + * @param textBoxSize + * the size if the textbox + * @param checkBoxText + * the text shown next to the checkboxes + */ + public ExpandedUiWithCheckboxes(StringMessages stringMessages, ImageResource removeImage, + List suggestValues, String placeholderTextForAddTextbox, int textBoxSize, String checkBoxText) { + super(stringMessages, removeImage, suggestValues, placeholderTextForAddTextbox, textBoxSize); + this.checkBoxes = new ArrayList(); + this.checkBoxText = checkBoxText; + ress.css().ensureInjected(); + } + + /** + * Used for the css styles + */ + interface ListEditorResources extends ClientBundle { + @Source("ListEditor.gss") + ListEditorCSS css(); + } + + interface ListEditorCSS extends CssResource { + String checkBoxInvisible(); + + String checkBoxNormal(); + + String checkBoxError(); + } + + /** + * Returns the checkboxes,so they can be accessed from another class + * + * @returns the checkboxes + */ + public List getCheckBoxes() { + return checkBoxes; + } + + /** + * used to set the checkbox style from another class + * + * @returns String the StyleName of the style + */ + public static String getInvisibleStyle() { + return ress.css().checkBoxInvisible(); + } + + public static String getErrorStyle() { + return ress.css().checkBoxError(); + } + + public static String getNormalStyle() { + return ress.css().checkBoxNormal(); + } + + /** + * See {@link ExpandedListEditorUi#addRow(Object)} + */ + @Override + protected void addRow(ValueType newValue) { + super.addRow(newValue); + final CheckBox checkBox = new CheckBox(checkBoxText); + checkBox.setStylePrimaryName(getInvisibleStyle()); + checkBox.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + CheckBox source = (CheckBox) event.getSource(); + if (source.getValue()) { + source.setStylePrimaryName(getNormalStyle()); + } else { + source.setStylePrimaryName(getErrorStyle()); + } + for (ChangeHandler changeHandler : ExpandedUiWithCheckboxes.this.changeHandler) { + changeHandler.onChange(null); + } + } + }); + checkBoxes.add(checkBox); + expandedValuesGrid.setWidget(expandedValuesGrid.getRowCount() - 1, 2, checkBox); + } + + /** + * See {@link ListEditorUiStrategy#initWidget()} + */ + @Override + public Widget initWidget() { + expandedValuesGrid = new Grid(0, 3); + expandedValuesGrid.ensureDebugId("ExpandedValuesGrid"); + + VerticalPanel panel = new VerticalPanel(); + panel.add(createAddWidget()); + panel.add(expandedValuesGrid); + return panel; + + } + + /** + * See {@link ListEditorUiStrategy#onRowRemoved(int)} + */ + @Override + public void onRowRemoved(int rowIndex) { + checkBoxes.remove(rowIndex); + } + + public void addChangeHandler(ChangeHandler handler) { + changeHandler.add(handler); + } +} diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditor.gss b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditor.gss new file mode 100644 index 00000000000..ca4a59596b0 --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditor.gss @@ -0,0 +1,23 @@ +.checkBoxInvisible { + visibility : hidden; + background-color : red; + padding: 3px; + padding-right: 5px; + padding-bottom: 4px; +} + +.checkBoxNormal { + visibility : visible; + background-color : white; + padding: 3px; + padding-right: 5px; + padding-bottom: 4px; +} + +.checkBoxError { + visibility : visible; + background-color : red; + padding: 3px; + padding-right: 5px; + padding-bottom: 4px; +} \ No newline at end of file diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditorUiStrategy.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditorUiStrategy.java index 1981cf9015f..314f9e56559 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditorUiStrategy.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditorUiStrategy.java @@ -10,7 +10,7 @@ import com.google.gwt.user.client.ui.Widget; * {@link ListEditorComposite#getValue() values} of the context editor that was passed to * {@link #setContext(ListEditorComposite)} during editor initialization.

    * - * Objects will receive calls to {@link #onRowAdded()} when a value was added to the list, and {@link #onRowRemoved()} when + * Objects will receive calls to {@link #onRowAdded()} when a value was added to the list, and {@link #onRowRemoved(int)} when * a value was removed from the list.

    * * There are two default implementations of this interface: {@link CollapsedListEditorUi} and {@link ExpandedListEditorUi}. @@ -54,6 +54,7 @@ public interface ListEditorUiStrategy { /** * Called by the framework after a value was removed from the list. Note that this is not the place for this UI * strategy to actually implement the UI changes. Those are expected to already have happened before. + * @param rowIndex The index of the removed row */ - void onRowRemoved(); + void onRowRemoved(int rowIndex); } \ No newline at end of file diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/filestorage/FileStorageManagementGwtService.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/filestorage/FileStorageManagementGwtService.java index 0ad38080e53..d2e92c7fef5 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/filestorage/FileStorageManagementGwtService.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/filestorage/FileStorageManagementGwtService.java @@ -19,6 +19,8 @@ public interface FileStorageManagementGwtService extends RemoteService { FileStorageServiceDTO[] getAvailableFileStorageServices(String localeInfoName); /** + * If serviceName is null, calls {@link FileStorageManagementGwtService#getActiveFileStorageServiceName()} and uses the returned name + * * @throws NoCorrespondingServiceRegisteredException service may have disappeared from registry in the meantime */ FileStorageServicePropertyErrorsDTO testFileStorageServiceProperties(String serviceName, String localeInfoName) throws NoCorrespondingServiceRegisteredException, IOException; diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java index 10edb3175c0..9468bbeb416 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java @@ -25,6 +25,7 @@ public abstract class AbstractMediaDTO implements IsSerializable, Comparable resizingTask; + + /** for GWT */ + @Deprecated + protected ImageResizingTaskDTO() { + } + + /** + * Creates an {@link ImageDTO} from the parameters + * + * @param imageRef + * needed for creating ImageDTO + * @param createdAtDate + * needed for creating ImageDTO + * @param resizingTask + * stored Information about resizing + */ + public ImageResizingTaskDTO(String imageRef, Date createdAtDate, List resizingTask) { + this(new ImageDTO(imageRef, createdAtDate), resizingTask); + } + + /** + * + * @param image + * the stored ImageDTO + * @param resizingTask + * stored Information about resizing + */ + public ImageResizingTaskDTO(ImageDTO image, List resizingTask) { + this.image = image; + this.resizingTask = resizingTask; + } + + /** + * @returns the ImageDTO + */ + public ImageDTO getImage() { + return image; + } + + /** + * @returns the List of MediaTagConstants + */ + public List getResizingTask() { + return resizingTask; + } + + /** + * Creates a clone of the ImageDTo with new references, so they do not interfere Used for resizing to edit + * afterwards, to easily copy all data from the original ImageDTO + * + * @returns a clone of the ImageDTO + */ + public ImageDTO cloneImageDTO() { + final ImageDTO toReturn = new ImageDTO(image.getSourceRef(), image.getCreatedAtDate()); + toReturn.setTitle(image.getTitle()); + toReturn.setCopyright(image.getCopyright()); + toReturn.setLocale(image.getLocale()); + // creating a new mimetype object so they do not use the same reference + toReturn.setMimeType(MimeType.byName(image.getMimeType().name())); + toReturn.setSizeInPx(image.getWidthInPx(), image.getHeightInPx()); + toReturn.setSubtitle(image.getSubtitle()); + // Creating a new list, so they have the same tags, but not use the same reference to these tags, otherwise they + // could affect each other by editing this list + final List tags = new ArrayList<>(); + tags.addAll(image.getTags()); + toReturn.setTags(tags); + return toReturn; + } +} \ No newline at end of file diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java index 007b51faf10..4915d8c22df 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java @@ -10,6 +10,7 @@ public class VideoDTO extends AbstractMediaDTO { private String thumbnailRef; /** for GWT */ + @Deprecated protected VideoDTO() { } @@ -34,7 +35,7 @@ public class VideoDTO extends AbstractMediaDTO { } public boolean isFeatured() { - return hasTag(MediaTagConstants.FEATURED); + return hasTag(MediaTagConstants.FEATURED.getName()); } @Override diff --git a/java/com.sap.sse.security.ui/build.properties b/java/com.sap.sse.security.ui/build.properties old mode 100644 new mode 100755 diff --git a/java/com.sap.sse.test/src/com/sap/sse/test/ImageConverterTest.java b/java/com.sap.sse.test/src/com/sap/sse/test/ImageConverterTest.java new file mode 100644 index 00000000000..48548f6dc80 --- /dev/null +++ b/java/com.sap.sse.test/src/com/sap/sse/test/ImageConverterTest.java @@ -0,0 +1,79 @@ +package com.sap.sse.test; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import com.sap.sse.util.ImageConverter; +import com.sap.sse.util.ImageConverter.ImageWithMetadata; + +/** + * + * @author Robin Fleige(D067799) + * + */ +public class ImageConverterTest { + private ImageConverter converter; + private ImageWithMetadata pngImage; + private ImageWithMetadata jpgImage; + + private final byte[] onePixelPngExample = new byte[]{-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0, 1, 8, 2, 0, 0, 0, -112, 119, 83, -34, 0, 0, 0, 12, 73, 68, 65, 84, 120, -38, 99, 96, 96, 96, 0, 0, 0, 4, 0, 1, -56, -22, -21, -7, 0, 0, 0, 0, 73, 69, 78, 68, -82, 66, 96, -126}; + private final byte[] onePixelJpgExample = new byte[]{-1, -40, -1, -32, 0, 16, 74, 70, 73, 70, 0, 1, 2, 0, 0, 1, 0, 1, 0, 0, -1, -37, 0, 67, 0, 8, 6, 6, 7, 6, 5, 8, 7, 7, 7, 9, 9, 8, 10, 12, 20, 13, 12, 11, 11, 12, 25, 18, 19, 15, 20, 29, 26, 31, 30, 29, 26, 28, 28, 32, 36, 46, 39, 32, 34, 44, 35, 28, 28, 40, 55, 41, 44, 48, 49, 52, 52, 52, 31, 39, 57, 61, 56, 50, 60, 46, 51, 52, 50, -1, -37, 0, 67, 1, 9, 9, 9, 12, 11, 12, 24, 13, 13, 24, 50, 33, 28, 33, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, -1, -64, 0, 17, 8, 0, 1, 0, 1, 3, 1, 34, 0, 2, 17, 1, 3, 17, 1, -1, -60, 0, 31, 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, -60, 0, -75, 16, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125, 1, 2, 3, 0, 4, 17, 5, 18, 33, 49, 65, 6, 19, 81, 97, 7, 34, 113, 20, 50, -127, -111, -95, 8, 35, 66, -79, -63, 21, 82, -47, -16, 36, 51, 98, 114, -126, 9, 10, 22, 23, 24, 25, 26, 37, 38, 39, 40, 41, 42, 52, 53, 54, 55, 56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 118, 119, 120, 121, 122, -125, -124, -123, -122, -121, -120, -119, -118, -110, -109, -108, -107, -106, -105, -104, -103, -102, -94, -93, -92, -91, -90, -89, -88, -87, -86, -78, -77, -76, -75, -74, -73, -72, -71, -70, -62, -61, -60, -59, -58, -57, -56, -55, -54, -46, -45, -44, -43, -42, -41, -40, -39, -38, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -1, -60, 0, 31, 1, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, -60, 0, -75, 17, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119, 0, 1, 2, 3, 17, 4, 5, 33, 49, 6, 18, 65, 81, 7, 97, 113, 19, 34, 50, -127, 8, 20, 66, -111, -95, -79, -63, 9, 35, 51, 82, -16, 21, 98, 114, -47, 10, 22, 36, 52, -31, 37, -15, 23, 24, 25, 26, 38, 39, 40, 41, 42, 53, 54, 55, 56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 118, 119, 120, 121, 122, -126, -125, -124, -123, -122, -121, -120, -119, -118, -110, -109, -108, -107, -106, -105, -104, -103, -102, -94, -93, -92, -91, -90, -89, -88, -87, -86, -78, -77, -76, -75, -74, -73, -72, -71, -70, -62, -61, -60, -59, -58, -57, -56, -55, -54, -46, -45, -44, -43, -42, -41, -40, -39, -38, -30, -29, -28, -27, -26, -25, -24, -23, -22, -14, -13, -12, -11, -10, -9, -8, -7, -6, -1, -38, 0, 12, 3, 1, 0, 2, 17, 3, 17, 0, 63, 0, -9, -6, 40, -94, -128, 63, -1, -39}; + + private final int baseSize = 100; + private final int halfSize = baseSize / 2; + private final int doubleSize = baseSize * 2; + private final int minSize = 0; + + /** + * Setting up the testing environment + */ + @Before + public void setUp() { + converter = new ImageConverter(); + pngImage = converter.loadImage(new ByteArrayInputStream(onePixelPngExample), "png"); + jpgImage = converter.loadImage(new ByteArrayInputStream(onePixelJpgExample), "jpg"); + } + + /** + * Tests the calculation of the dimensions, which is used for resizing the image to a fitting size + */ + @Test + public void testCalculateDimensions() { + int[] dimensions; + dimensions = converter.calculateDimensions(baseSize, baseSize, halfSize, doubleSize, halfSize, doubleSize); + assertEquals(dimensions[0], baseSize); + assertEquals(dimensions[1], baseSize); + dimensions = converter.calculateDimensions(baseSize, baseSize, minSize, halfSize, minSize, halfSize); + assertEquals(dimensions[0], halfSize); + assertEquals(dimensions[1], halfSize); + dimensions = converter.calculateDimensions(baseSize, doubleSize, minSize, halfSize, minSize, halfSize); + assertTrue(dimensions[0] < halfSize); + assertEquals(dimensions[1], halfSize); + dimensions = converter.calculateDimensions(minSize, minSize, halfSize, baseSize, halfSize, baseSize); + assertNull(dimensions); + } + + /** + * Tests the conversions that are done while resizing an image + * + * @throws IOException + */ + @Test + public void testConversions() throws IOException { + byte[] byteArray; + byteArray = converter.inputStreamToByteArray( + converter.imageWithMetadataToInputStream(jpgImage.getImage(), jpgImage.getMetadata(), "jpg")); + assertArrayEquals(onePixelJpgExample, byteArray); + byteArray = converter.inputStreamToByteArray( + converter.imageWithMetadataToInputStream(pngImage.getImage(), pngImage.getMetadata(), "png")); + assertArrayEquals(onePixelPngExample, byteArray); + } +} diff --git a/java/com.sap.sse/src/com/sap/sse/util/ImageConverter.java b/java/com.sap.sse/src/com/sap/sse/util/ImageConverter.java new file mode 100644 index 00000000000..fe58f34d9d8 --- /dev/null +++ b/java/com.sap.sse/src/com/sap/sse/util/ImageConverter.java @@ -0,0 +1,432 @@ +package com.sap.sse.util; + +import static java.lang.Math.toIntExact; + +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +import com.sap.sse.common.Base64Utils; +import com.sap.sse.common.media.MediaTagConstants; + +/** + * /** An Utility Class to help resizing an image + * + * @author Robin Fleige (D067799) + */ +public class ImageConverter { + private static final Logger logger = Logger.getLogger(ImageConverter.class.getName()); + + /** + * Writes a BufferedImage to an InputStream. This should only be used as a backup, if + * {@link ImageConverter#imageWithMetadataToInputStream(BufferedImage, IIOMetadata, String)} fails + * + * @param image + * The BufferedImage that should be converted + * @param imageFormat + * the format of the image, for example "png", "jpeg" or "jpg" + * @returns an InputStream with the Information of the Image + * @throws IOException + */ + private InputStream imageToInputStream(final BufferedImage image, final String imageFormat) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try { + ImageIO.write(image, imageFormat, bos); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getMessage()); + } + final byte[] arr = bos.toByteArray(); + return new ByteArrayInputStream(arr); + } + + /** + * Resizes an BufferedImage, so it fits into the defined bounds without changing the width-height-ratio. The image + * is kept as large as possible inside this bounds. + * + * @param image + * The BufferedImage that should be resized + * @param minWidth + * the minimum width the image should have after resizing + * @param maxWidth + * the maximum width the image should have after resizing + * @param minHeight + * the minimum height the image should have after resizing + * @param maxHeight + * the maximum height the image should have after resizing + * @returns the resized BufferedImage. Returns null, if BufferedImage is null, or if the defined bounds do not fit + * the image + */ + public BufferedImage resize(final BufferedImage image, final int minWidth, final int maxWidth, final int minHeight, + final int maxHeight) { + final int[] dimensions = calculateDimensions(image.getWidth(), image.getHeight(), minWidth, maxWidth, minHeight, + maxHeight); + final BufferedImage resizedImage; + if (dimensions != null) { + resizedImage = resize(image, dimensions[0], dimensions[1]); + } else { + resizedImage = null; + } + return resizedImage; + } + + /** + * Calculates the dimensions of an image, so it fits inside the defined bounds without changing the + * width-height-ratio. Keeps it as big as possible + * + * @param width + * the current width of the image that should be resized + * @param height + * the current height of the image that should be resized + * @param minWidth + * the minimum width the image should have after resizing + * @param maxWidth + * the maximum width the image should have after resizing + * @param minHeight + * the minimum height the image should have after resizing + * @param maxHeight + * the maximum height the image should have after resizing + * @returns an array of two integers, where the first entry is the fitting width and the second is the fitting + * height. returns null, if the defined bounds do not fit the current size + */ + public int[] calculateDimensions(final double width, final double height, final double minWidth, + final double maxWidth, final double minHeight, final double maxHeight) { + int[] dimensions = new int[2]; + if (maxWidth >= 0 && maxHeight >= 0 && maxHeight > minHeight && maxWidth > minWidth && width > minWidth + && height > minHeight) { + if (maxWidth <= width || maxHeight <= height) { + if (width / maxWidth > height / maxHeight) { + dimensions[1] = (int) maxWidth; + dimensions[1] = (int) (height / width * maxWidth); + if (dimensions[1] >= minHeight) { + dimensions[0] = (int) maxWidth; + } else { + dimensions = null; + } + } else { + dimensions[0] = (int) (width / height * maxHeight); + if (dimensions[0] >= minWidth) { + dimensions[1] = (int) maxHeight; + } else { + dimensions = null; + } + } + } else { + dimensions[0] = (int) width; + dimensions[1] = (int) height; + } + } else { + dimensions = null; + } + return dimensions; + } + + /** + * Resizes an BufferedImage, to the width and height. + * + * @param image + * The BufferedImage that should be resized + * @param demandWidth + * the width the image should have after resizing + * @param demandHeight + * the height the image should have after resizing + * @returns the resized BufferedImage. Returns null, if BufferedImage is null + */ + private BufferedImage resize(final BufferedImage image, final int demandedWidth, final int demandedHeight) { + final BufferedImage resizedImage = new BufferedImage((int) demandedWidth, (int) demandedHeight, + image.getType()); + final Graphics2D g = resizedImage.createGraphics(); + final AffineTransform transform = new AffineTransform(); + transform.scale((double) demandedWidth / image.getWidth(), (double) demandedHeight / image.getHeight()); + final BufferedImageOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR); + g.drawImage(image, op, 0, 0); + g.dispose(); + return resizedImage; + } + + /** + * Creates an InputStream from a BufferedImage, the IIOMetadata of the image and the imageFormat + * + * @param bufferdImage + * the image that has to be written to an InputStream + * @param metadata + * the IIOMetadata that should be stored in the InputStream with the BufferedImage + * @param imageFormat + * the format of the image, for example "png", "jpeg" or "jpg" + * @throws IOException + * @returns an InputStream with the data of the BufferedImage and if possible with the IIOMetadata. Returns null if + * the image is null or the imageFormat is incorrect + */ + public InputStream imageWithMetadataToInputStream(final BufferedImage bufferdImage, final IIOMetadata metadata, + final String imageFormat) throws IOException { + byte[] bytes = null; + if (metadata != null) { + // trying to obtain OutputStream of the image with EXIF data + try (ImageOutputStream ios = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) { + // the following should write the exif data of the image to all copies of the image, it should already + // work, but due to a bug the data array stays empty + final Iterator writers = ImageIO.getImageWritersBySuffix(imageFormat); + while (writers.hasNext() && bytes == null) { + final ImageWriter writer = writers.next(); + if (writer != null) { + writer.setOutput(ios); + final IIOImage iioImage = new IIOImage(bufferdImage, null, metadata); + final ImageWriteParam param = writer.getDefaultWriteParam(); + final IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(param); + writer.write(streamMetadata, iioImage, param); + writer.dispose(); + bytes = new byte[toIntExact(ios.length())]; + ios.read(bytes); + if (isZeroByteArray(bytes)) { + bytes = null; + } + } + } + if (bytes == null) { + throw new Exception( + "Saving file via FileWriter did not work, not able to write file with metadata, retrying with ImageIO.write()"); + } + } catch (Exception e) { + bytes = null; + logger.log(Level.INFO, e.getMessage()); + } // if obtaining an OutputStream if the image with EXIF data did not work, then write it without + } + final InputStream toReturn; + if (bytes == null) { + toReturn = imageToInputStream(bufferdImage, imageFormat); + } else {// if it did work, then write the OutputStream to the FileStorageService + toReturn = new ByteArrayInputStream(bytes); + } + return toReturn; + } + + /** + * Writes an inputstream into a ByteArray + * + * @param inputStream + * the inputstream that should be stored in the ByteArray + * @returns an Array of Bytes with the data of the inputstream + */ + public byte[] inputStreamToByteArray(final InputStream inputStream) { + byte[] byteArray = null; + try { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[1024]; + while ((nRead = inputStream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + buffer.flush(); + byteArray = buffer.toByteArray(); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getMessage()); + } + return byteArray; + } + + /** + * Checks if a byte array only contains zeros + * + * @param bytes + * an byte array + * @returns true if the byte array is null, empty or only contains zeros, otherwise false + */ + private boolean isZeroByteArray(final byte[] bytes) { + boolean toReturn = true; + if (bytes != null) { + for (int i = 0; i < bytes.length; i++) { + if (bytes[i] != 0) { + toReturn = false; + } + } + } + return toReturn; + } + + /** + * Converts an InputStream that contains an image to a Base64 String + * + * @param inputStream + * the InputStream that should be converted + * @param imageFormat + * the format of the image, for example "png", "jpeg" or "jpg" + * @returns the Base64 representation of the InputStream + * @throws IOException + */ + public String convertToBase64(final InputStream inputStream, final String imageFormat) throws IOException { + return convertToBase64(bufferedImageToByteArray(loadBufferedImageFromInputStream(inputStream), imageFormat)); + } + + /** + * Converts an BufferedImage to a Base64 String + * + * @param image + * the image that should be converted as a BufferedImage + * @param imageFormat + * the format of the image, for example "png", "jpeg" or "jpg" + * @returns the Base64 representation of the image + * @throws IOException + */ + public String convertToBase64(final BufferedImage image, final String imageFormat) throws IOException { + return convertToBase64(bufferedImageToByteArray(image, imageFormat)); + } + + /** + * Converts an array of bytes to a Base64 String + * + * @param bytes + * an array of bytes + * @returns the Base64 representation of the byte array + */ + private String convertToBase64(final byte[] bytes) { + return Base64Utils.toBase64(bytes); + } + + /** + * Converts an InputStream to a BufferedImage. This should only be used as a backup, if + * {@link ImageConverter#loadImage(InputStream, String)} fails + * + * @param inputStream + * @return + */ + private BufferedImage loadBufferedImageFromInputStream(final InputStream inputStream) { + BufferedImage image = null; + try { + image = ImageIO.read(inputStream); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getMessage()); + } + return image; + } + + // looses metadata, so should not be used for storing an image, but only for showing an image + /** + * Converts an BufferedImage to a ByteArray that contains all of its information This Method does not use the + * IIOMetadata of the original image, so it should not be used to store images, but only for showing them. To also + * use the IIOMetadata of the image use the @link + * {@link ImageConverter#imageWithMetadataToInputStream(BufferedImage, IIOMetadata, String)} and then the @link + * {@link ImageConverter#inputStreamToByteArray(InputStream)} method + * + * @param image + * the image that should be converted to a ByteArray + * @param imageFormat + * the format of the image, for example "png", "jpeg" or "jpg" + * @returns an ByteArray with all the information of the image + */ + public byte[] bufferedImageToByteArray(final BufferedImage image, final String imageFormat) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + ImageIO.write(image, imageFormat, baos); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getMessage()); + } + return baos.toByteArray(); + } + + /** + * Converts one BufferedImage to a list of at least one BufferedImage with different sizes as described in the given + * {@link MediaTagConstants} + * + * @param image + * the image that should be converted + * @param resizingTasks + * a List of {@link MediaTagConstants} that define to which size the image should be resized + * @returns a list of BufferedImages, that contains as many BufferedImages as resizingTask contains + * {@link MediaTagConstants} + */ + public List convertImage(final BufferedImage image, final List resizingTasks) { + final List resizedImages = new ArrayList<>(); + for (MediaTagConstants tag : resizingTasks) { + resizedImages + .add(resize(image, tag.getMinWidth(), tag.getMaxWidth(), tag.getMinHeight(), tag.getMaxHeight())); + } + return resizedImages; + } + + /** + * Loads an BufferedImage and the IIOMetadata from an InputStream that contains an image. + * + * @param inputStream + * the InputStream that contains the image and the metadata + * @param imageFormat + * the format of the image, for example "png", "jpeg" or "jpg" + * @returns an {@link ImageWithMetadata} that contains the BufferedImage and the IIOMetadata of the image If the + * loading of the IIOMetadata does not work, returns an {@link ImageWithMetadata} where metadata is null + */ + public ImageWithMetadata loadImage(final InputStream inputStream, final String imageFormat) { + // trying to receive the EXIF data and loading the image. If this does not work only the image is loaded + final ImageConverter converter = new ImageConverter(); + BufferedImage image = null; + IIOMetadata metadata = null; + boolean loaded = false; + byte[] bytes = converter.inputStreamToByteArray(inputStream); + try { + final Iterator readerIterator = ImageIO.getImageReadersBySuffix(imageFormat); + while (readerIterator.hasNext() && !loaded) { + final ImageReader reader = readerIterator.next(); + reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(bytes))); + metadata = reader.getImageMetadata(0); + image = reader.read(0); + loaded = metadata != null; + } + if (!loaded) { + throw new Exception( + "Loading file via ImageReader did not work, not able to load metadata, retrying to load with ImageIO.read()"); + } + } catch (Exception e) { + logger.log(Level.INFO, e.getMessage()); + } + if (!loaded) { + image = converter.loadBufferedImageFromInputStream(new ByteArrayInputStream(bytes)); + metadata = null; + } + try { + inputStream.close(); + } catch (IOException e) { + logger.log(Level.WARNING, "Potential ressource leak"); + } + return new ImageWithMetadata(image, metadata); + } + + /** + * A Data Storage class to store an BufferedImage and IIOMetadata + * + * @author Robin Fleige (D067799) + * + */ + public class ImageWithMetadata { + private final BufferedImage image; + private final IIOMetadata metadata; + + public ImageWithMetadata(BufferedImage image, IIOMetadata metadata) { + this.image = image; + this.metadata = metadata; + } + + public BufferedImage getImage() { + return image; + } + + public IIOMetadata getMetadata() { + return metadata; + } + } +} diff --git a/wiki/info/landscape/typical-development-scenarios.md b/wiki/info/landscape/typical-development-scenarios.md index 6abddf0d611..8ab41fb9a85 100644 --- a/wiki/info/landscape/typical-development-scenarios.md +++ b/wiki/info/landscape/typical-development-scenarios.md @@ -14,6 +14,7 @@ We distinguish two cases: adding a 3rd-party bundle to the target platform and a * Go to directory 'java/com.sap.sailing.targetplatform/scripts' * Rebuild the base target platform by running the script 'createLocalBaseP2repository.sh' * Generate the target definition for this local repository by running the script 'createLocalTargetDef.sh' + * Currently this scripts work for the cygwin shell and the git bash, if the path to your files in the target definition is incorrect, this may be the reason. * Test the new overall target platform * by setting the race-analysis-p2-local.target as target platform in the IDE * by running the local maven build via ''buildAndUpdateProduct.sh -v build'' (the ''-v'' switch builds and uses the local p2 repository)