How to impose control over vertex-to-vertex Graph edges?

For example:

g1 = Graph[softwareapplication, VertexLabels -> vertexlabels, 
          EdgeLabels -> edgelabels, VertexSize -> Small, ImageSize -> Medium,
          VertexCoordinates -> {{0, 2}, {-1, 1}, {1, 1}, {0, 0}}, 
          EdgeShapeFunction -> Automatic];
PropertyValue[{g1, 4 \[DirectedEdge] 1}, EdgeShapeFunction] = 
      ({Red, Arrowheads[{{.02, .98}}], Arrow@BezierCurve[Riffle[#1, {{4, 1}}]]} &);
g1

Mathematica graphics


Update: Using the process softwareapplication as the first argument in Graph and setting EdgeLabels based on the transition matrix of the process, we can do everything in one step:

Graph[softwareapplication, 
   EdgeShapeFunction -> {DirectedEdge[4, 1] -> 
   ({Red, Arrow[GraphElementData[{"CurvedArc", "Curvature" -> -4}][##], .1]} &)}, 
   EdgeLabels -> {DirectedEdge[i_, j_] :> 
    MarkovProcessProperties[softwareapplication, "TransitionMatrix"][[i, j]]}]

enter image description here

Original answer:

You can also use the built-in (and undocumented) edge shape function "CurvedArc":

SetProperty[{g1, 4 -> 1},  EdgeShapeFunction -> 
 ({Red, Arrow[GraphElementData[{"CurvedArc", "Curvature" -> -4}][##], .1]} &)]

enter image description here